--- /dev/null
+type encoding = Utf8 | Binary
+
+type lfstyle = Unix | Dos
+
+type bufinfo = {
+ path: string;
+ modtime: int;
+ charset: encoding;
+ crlf: lfstyle;
+}
+
+type bufstate = {
+ nlines : int;
+ outpoint : int;
+ rope : Rope.t
+}
+
+type buf = {
+ info : bufinfo;
+ current : bufstate;
+ lastsave : bufstate;
+ undo : bufstate list;
+ redo : bufstate list;
+}
+
+let create =
+ let state = { nlines = 0; outpoint = 0; rope = Rope.empty }
+ and info = { path = ""; modtime = 0; charset = Utf8; crlf = Unix } in
+ { info = info; current = state; lastsave = state; undo = []; redo = [] }
+
+let load path =
+ create
+
+let saveas buf path =
+ ()
+
+let save buf =
+ saveas buf buf.info.path
+
+(*
+
+/* cursor/selection representation */
+typedef struct {
+ size_t beg;
+ size_t end;
+ size_t col;
+} Sel;
+
+void buf_init(Buf* buf, void ( *errfn )( char* ));
+size_t buf_load(Buf* buf, char* path);
+void buf_reload(Buf* buf);
+void buf_save(Buf* buf);
+
+size_t buf_insert(Buf* buf, bool indent, size_t off, Rune rune);
+size_t buf_delete(Buf* buf, size_t beg, size_t end);
+
+void buf_undo(Buf* buf, Sel* sel);
+void buf_redo(Buf* buf, Sel* sel);
+
+Rune buf_get(Buf* buf, size_t pos);
+size_t buf_end(Buf* buf);
+
+size_t buf_change(Buf* buf, size_t beg, size_t end);
+void buf_chomp(Buf* buf);
+void buf_loglock(Buf* buf);
+void buf_logclear(Buf* buf);
+bool buf_iseol(Buf* buf, size_t pos);
+size_t buf_bol(Buf* buf, size_t pos);
+size_t buf_eol(Buf* buf, size_t pos);
+size_t buf_bow(Buf* buf, size_t pos);
+size_t buf_eow(Buf* buf, size_t pos);
+size_t buf_lscan(Buf* buf, size_t pos, Rune r);
+size_t buf_rscan(Buf* buf, size_t pos, Rune r);
+void buf_getword(Buf* buf, bool ( *isword )(Rune), Sel* sel);
+void buf_getblock(Buf* buf, Rune beg, Rune end, Sel* sel);
+size_t buf_byrune(Buf* buf, size_t pos, int count);
+size_t buf_byword(Buf* buf, size_t pos, int count);
+size_t buf_byline(Buf* buf, size_t pos, int count);
+void buf_findstr(Buf* buf, int dir, char* str, size_t* beg, size_t* end);
+void buf_lastins(Buf* buf, size_t* beg, size_t* end);
+size_t buf_setln(Buf* buf, size_t line);
+size_t buf_getln(Buf* buf, size_t off);
+size_t buf_getcol(Buf* buf, size_t pos);
+size_t buf_setcol(Buf* buf, size_t pos, size_t col);
+
+*)
--- /dev/null
+exception Out_of_bounds of string
+
+type rope =
+ | Leaf of string * int * int
+ | Node of rope * rope * int
+
+type t = rope
+
+let empty = Leaf ("", 0, 0)
+
+let length = function
+ | Leaf (_,_,l) -> l
+ | Node (_,_,l) -> l
+
+let from_string s =
+ Leaf (s, 0, (String.length s))
+
+let check_index rope i =
+ if i < 0 || i >= (length rope) then
+ raise (Out_of_bounds "Rope.check_index")
+
+let join left right =
+ let left_len = (length left) in
+ let right_len = (length right) in
+ if left_len == 0 then right
+ else if right_len == 0 then left
+ else Node (left, right, (length left) + (length right))
+
+let rec split rope i =
+ if i < 0 || i > (length rope) then
+ raise (Out_of_bounds "Rope.split");
+ match rope with
+ | Leaf (s,off,len) ->
+ (Leaf (s, off, i), Leaf (s, (off + i), len - (i)))
+ | Node (l,r,len) ->
+ let left_len = (length l) in
+ if i < left_len then
+ let (sl,sr) = (split l i) in
+ (sl, (join sr r))
+ else
+ let (sl,sr) = (split r i) in
+ ((join l sl), sr)
+
+let rec getc rope i =
+ check_index rope i;
+ match rope with
+ | Leaf (s,off,len) -> s.[off + i]
+ | Node (l,r,len) ->
+ let left_len = (length l) in
+ if i < left_len then
+ getc l i
+ else
+ getc r (i - left_len)
+
+let rec puts rope s i =
+ let (left,right) = split rope i in
+ let middle = from_string s in
+ (join (join left middle) right)
+
+let del rope i j =
+ let (l_left,l_right) = split rope i in
+ let (r_left,r_right) = split l_right (j - i) in
+ (join l_left r_right)
+
+module Iter = struct
+ type t = {
+ rope: rope;
+ length: int;
+ mutable pos: int;
+ }
+
+ let make rope index =
+ check_index rope index;
+ { rope = rope; length = (length rope); pos = index }
+
+ let pos itr = itr.pos
+
+ let incr itr = itr.pos <- (itr.pos + 1)
+
+ let decr itr = itr.pos <- (itr.pos - 1)
+
+ let goto itr pos= itr.pos <- pos
+
+ let move itr off = itr.pos <- (itr.pos + off)
+
+ let get itr = getc itr.rope itr.pos
+
+ let has_next itr = (itr.pos + 1) <= itr.length
+
+ let has_prev itr = (itr.pos - 1) > 0
+end
+
+let iteri fn rope =
+ let it = Iter.make rope 0 in
+ while (Iter.has_next it) do
+ fn (Iter.pos it) (Iter.get it);
+ Iter.incr it
+ done
+
+let iter fn rope =
+ iteri (fun i c -> (fn c)) rope
+
+let map fn rope =
+ let buf = Bytes.create (length rope) in
+ iteri (fun i c -> Bytes.set buf i (fn c)) rope;
+ from_string (Bytes.unsafe_to_string buf)
+
+let mapi fn rope =
+ let buf = Bytes.create (length rope) in
+ iteri (fun i c -> Bytes.set buf i (fn i c)) rope;
+ from_string (Bytes.unsafe_to_string buf)
+
+let gets rope i j =
+ let buf = Bytes.create (j - i)
+ and it = Iter.make rope 0 in
+ while (Iter.has_next it) && ((Iter.pos it) <= j) do
+ Bytes.set buf ((Iter.pos it) - i) (Iter.get it);
+ Iter.incr it;
+ done;
+ Bytes.unsafe_to_string buf
+
+let to_string rope =
+ gets rope 0 (length rope)