let expand (v : Ed_sourceview.sourceview) args =
  let f = v#file in
  let b = f#buffer in 
  let cur_iter = b#get_iter `INSERT in
  let pos = cur_iter#offset in
  let ctx =
    match !context with
      None ->
        let (pat,rex) = get_pattern v cur_iter in 
        let c = create_context f#name pos pat rex in
        context := Some c;
        c
    | Some c ->
        if (not (Cam_commands.same_previous_command ())) or
          c.buffer <> f#name or c.pos <> pos
        then
          (
           let (pat, rex) = get_pattern v cur_iter in
           let c = create_context f#name pos pat rex in
           context := Some c;
           c
          )
        else
          c
  in
  match get_next_proposition ctx with
    None ->
      Ed_misc.warning_message "No expansion found."
  | Some (cycle, s) ->
      if cycle then
        Ed_misc.warning_message "No more expansion found, restarting from beginning.";
      (* eventually remove the previous string inserted *)
      let insert_iter =
        let s_to_remove =
          match ctx.prev_inserted with
            None -> ctx.searched_pattern
          | Some s -> s
        in
        (* we're supposed to be at the end of the (previously inserted) text *)
        let stop = cur_iter in
        let len = Cam_misc.utf8_string_length s_to_remove in
        let start = stop#backward_chars len in
        b#delete ~start ~stop;
        b#get_iter (`OFFSET (pos - len))
      in
      b#place_cursor ~where: insert_iter;
      b#insert s;
      let pos = (b#get_iter `INSERT)#offset in
      ctx.pos <- pos;
      ctx.prev_inserted <- Some s