]> git.mdlowis.com Git - archive/tide-ocaml.git/commitdiff
Added preliminary buffer implementation based on a naive rope implementation
authorMichael D. Lowis <mike.lowis@gentex.com>
Wed, 27 Sep 2017 18:22:17 +0000 (14:22 -0400)
committerMichael D. Lowis <mike.lowis@gentex.com>
Wed, 27 Sep 2017 18:22:17 +0000 (14:22 -0400)
Makefile
lib/buf.ml [new file with mode: 0644]
lib/rope.ml [new file with mode: 0644]

index e0a96cb9b4a8c75101a11a175b490f9a9159430e..40ab0eea9bd6f8c292f14c527dbb3b173b720b4f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,8 @@ LIBOBJS = \
     lib/x11.$(OBJEXT) \
     lib/cfg.$(OBJEXT) \
     lib/x11_prims.o \
+    lib/rope.$(OBJEXT) \
+    lib/buf.$(OBJEXT) \
     lib/utf8.o
 
 .PHONY: all clean
diff --git a/lib/buf.ml b/lib/buf.ml
new file mode 100644 (file)
index 0000000..421d31a
--- /dev/null
@@ -0,0 +1,86 @@
+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);
+
+*)
diff --git a/lib/rope.ml b/lib/rope.ml
new file mode 100644 (file)
index 0000000..acb9eda
--- /dev/null
@@ -0,0 +1,123 @@
+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)