]> git.mdlowis.com Git - archive/tide-ocaml.git/commitdiff
implemented tab handling
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 24 Oct 2017 02:34:04 +0000 (22:34 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 24 Oct 2017 02:34:04 +0000 (22:34 -0400)
edit.ml
lib/buf.ml
lib/rope.ml
lib/rope.sync-conflict-20171023-192447-NVTQWLE.ml [new file with mode: 0644]

diff --git a/edit.ml b/edit.ml
index 49f71af6f76003846c56ff682453093e7c56a628..6b52ecea96a0d6097974a279709afd81ceed3736 100644 (file)
--- a/edit.ml
+++ b/edit.ml
@@ -5,6 +5,9 @@ let font_monaco = font_load "Monaco:size=10::antialias=true:autohint=true"
 let font_verdana = font_load "Verdana:size=11:antialias=true:autohint=true"
 
 let font = font_verdana
+let tabglyph = 0x30
+let tabwidth = 4
+
 let tags_buf = ref Buf.empty
 let edit_buf = ref Buf.empty
 
@@ -58,6 +61,10 @@ let draw_buffer pos width height =
     (match c with
     | 0x0A -> newline ()
     | 0x0D -> ()
+    | 0x09 ->
+        let tabsz = ((X11.get_glyph font tabglyph).xoff * tabwidth) in
+        let ntabs = (width - pos.x) / tabsz in
+        x := pos.x + (((!x - pos.x) + tabsz) / tabsz * tabsz)
     | _    -> begin
         if (!x + glyph.xoff) > width then (newline ());
         let off = X11.draw_glyph Cfg.Color.palette.(5) glyph (!x, !y) in
@@ -70,7 +77,9 @@ let draw_buffer pos width height =
 
 let draw_edit pos width height =
   draw_dark_bkg (width - pos.x) (height - pos.y) pos;
-  draw_buffer { x = pos.x + 4; y = pos.y + 2} width height
+  let pos = { x = pos.x + 2; y = pos.y + 2 } in
+  Buf.redraw !edit_buf pos.x pos.y width height;
+  draw_buffer pos width height
 
 (* Event functions
  ******************************************************************************)
index a6be4564f341e107c744dd9f56e92c4072610c6b..c45d2388bb113230480031e2d665c657ef7b7d4d 100644 (file)
@@ -1,15 +1,8 @@
-type cursor = {
-  start : int;
-  stop : int
-}
+type cursor = { start : int; stop : int }
 
-type buf = {
-  path : string;
-  rope : Rope.t
-}
+type buf = { path : string; rope : Rope.t }
 
-let iter_from fn buf i =
-  Rope.iter_from fn buf.rope i
+let font = X11.font_load "Verdana:size=11:antialias=true:autohint=true"
 
 let empty =
   { path = ""; rope = Rope.empty }
@@ -17,6 +10,20 @@ let empty =
 let load path =
   { path = path; rope = Rope.from_string (Misc.load_file path) }
 
+let redraw buf x y width height =
+  (*let width = (width - x) in*)
+  let nlines = ((height - y) / font.height) in
+  ()
+
+let iter_from fn buf i =
+  Rope.iter_from fn buf.rope i
+
+
+
+
+
+(*
+
 let make_cursor buf start stop =
   { start = (Rope.limit_index buf.rope start);
     stop = (Rope.limit_index buf.rope stop) }
@@ -31,7 +38,7 @@ let move_word count csr buf ext =
 
 let move_line count csr buf ext =
   ()
-
+*)
 (* Unit Tests *****************************************************************)
 
 let run_unit_tests () =
index 333da3eb0a504e55b01062adda1756a1226e8621..e7facc496bb4f91d2042877006506ef975198f5d 100644 (file)
@@ -273,6 +273,13 @@ let run_unit_tests () =
     let rope = Leaf("abcd\n", 0, 5) in
     assert( (is_eol rope 2) == false );
   );
+
+  (* to_bol() tests *)
+  test "to_bol : should return index of first char on the line" (fun () ->
+    let rope = Leaf("\nabc\n", 0, 5) in
+    assert( (to_bol rope 2) == 1 );
+  );
+
   ()
 
 (*
diff --git a/lib/rope.sync-conflict-20171023-192447-NVTQWLE.ml b/lib/rope.sync-conflict-20171023-192447-NVTQWLE.ml
new file mode 100644 (file)
index 0000000..333da3e
--- /dev/null
@@ -0,0 +1,294 @@
+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 limit_index rope i =
+  if i < 0 then 0
+  else if i > 0 && i >= (length rope) then
+    ((length rope) - 1)
+  else i
+
+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,_) -> (Char.code 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 last rope =
+  limit_index rope ((length rope) - 1)
+
+let is_bol rope pos =
+  if pos == 0 then true
+  else ((getc rope (pos-1)) == 0x0A)
+
+let is_eol rope pos =
+  if pos >= (last rope) then true
+  else let c = (getc rope (pos+1)) in
+    (c == 0x0A || c == 0x0D)
+
+let is_bow rope pos = false
+
+let is_eow rope pos = false
+
+let rec move_till step testfn rope pos =
+  if (testfn rope pos) then pos
+  else (move_till step testfn rope (pos + step))
+
+let to_bol rope pos =
+  move_till (-1) is_bol rope pos
+
+let to_eol rope pos =
+  move_till (+1) is_eol rope pos
+
+let to_bow rope pos =
+  move_till (-1) is_bow rope pos
+
+let to_eow rope pos =
+  move_till (+1) is_eow rope pos
+
+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)
+
+let rec iter_from fn rope pos =
+  if pos < (length rope) && (fn (getc rope pos)) then
+    iter_from fn rope (pos + 1)
+
+let rec iteri_from fn rope pos =
+  if pos < (length rope) && (fn pos (getc rope pos)) then
+    iteri_from fn rope (pos + 1)
+
+let iteri fn rope =
+  iteri_from (fun i c -> (fn i c); true) rope 0
+
+let iter fn rope =
+  iter_from (fun c -> (fn c); true) rope 0
+
+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) in
+  iteri_from
+    (fun n c ->
+      Bytes.set buf (n - i) (Char.chr (getc rope i));
+      (n <= j))
+    rope i;
+  Bytes.unsafe_to_string buf
+
+let to_string rope =
+  gets rope 0 (length rope)
+
+(* Unit Tests *****************************************************************)
+
+let run_unit_tests () =
+  let open Test in
+  (* length() tests *)
+  test "length : 0 for empty string" (fun () ->
+    let rope = Leaf("", 0, 0) in
+    assert( length rope == 0 )
+  );
+  test "length : equal to length of leaf" (fun () ->
+    let rope = Leaf("a", 0, 1) in
+    assert( length rope == 1 )
+  );
+  test "length : equal to sum of leaf lengths" (fun () ->
+    let rope = (join (Leaf("a", 0, 1)) (Leaf("a", 0, 1))) in
+    assert( length rope == 2 )
+  );
+
+  (* join() tests *)
+  test "join : join two leaves into rope" (fun () ->
+    let left  = Leaf("a", 0, 1) in
+    let right =  Leaf("a", 0, 1) in
+    let rope  = (join left right) in
+    assert( match rope with
+    | Node (l,r,2) -> (l == left && r == right)
+    | _ -> false)
+  );
+  test "join : join a rope with a leaf (l to r)" (fun () ->
+    let left  = join (Leaf("a", 0, 1)) (Leaf("a", 0, 1)) in
+    let right =  Leaf("a", 0, 1) in
+    let rope  = (join left right) in
+    assert( match rope with
+    | Node (l,r,3) -> (l == left && r == right)
+    | _ -> false)
+  );
+  test "join : join a rope with a leaf (r to l)" (fun () ->
+    let left  =  Leaf("a", 0, 1) in
+    let right = join (Leaf("a", 0, 1)) (Leaf("a", 0, 1)) in
+    let rope  = (join left right) in
+    assert( match rope with
+    | Node (l,r,3) -> (l == left && r == right)
+    | _ -> false)
+  );
+
+  (* getc() tests *)
+  test "getc : raise Out_of_bounds on negative index" (fun () ->
+    let rope = Leaf("a", 0, 1) in
+    try getc rope (-1); assert false
+    with Out_of_bounds _ -> assert true
+  );
+  test "getc : raise Out_of_bounds on out of bounds index" (fun () ->
+    let rope = Leaf("a", 0, 1) in
+    try getc rope (2); assert false
+    with Out_of_bounds _ -> assert true
+  );
+  test "getc : return index 0 of leaf" (fun () ->
+    let rope = Leaf("abc", 0, 3) in
+    assert( (getc rope (0)) == Char.code 'a' );
+  );
+  test "getc : return index 1 of leaf" (fun () ->
+    let rope = Leaf("abc", 0, 3) in
+    assert( (getc rope (1)) == Char.code 'b' );
+  );
+  test "getc : return index 2 of leaf" (fun () ->
+    let rope = Leaf("abc", 0, 3) in
+    assert( (getc rope (2)) == Char.code 'c' );
+  );
+  test "getc : return index 0 of rope" (fun () ->
+    let rope = Node((Leaf("a", 0, 1)), (Leaf("b", 0, 1)), 2) in
+    assert( (getc rope (0)) == Char.code 'a' );
+  );
+  test "getc : return index 1 of rope" (fun () ->
+    let rope = Node((Leaf("a", 0, 1)), (Leaf("b", 0, 1)), 2) in
+    assert( (getc rope (1)) == Char.code 'b' );
+  );
+
+  (* puts() tests *)
+  test "puts : insert at index 0" (fun () ->
+    let rope = Leaf("bc", 0, 2) in
+    let rope = (puts rope "a" 0) in
+    assert( (length rope) == 3 );
+    assert( (getc rope (0)) == Char.code 'a' );
+    assert( (getc rope (1)) == Char.code 'b' );
+    assert( (getc rope (2)) == Char.code 'c' );
+  );
+  test "puts : insert at index 1" (fun () ->
+    let rope = Leaf("ac", 0, 2) in
+    let rope = (puts rope "b" 1) in
+    assert( (length rope) == 3 );
+    assert( (getc rope (0)) == Char.code 'a' );
+    assert( (getc rope (1)) == Char.code 'b' );
+    assert( (getc rope (2)) == Char.code 'c' );
+  );
+  test "puts : insert index at 2" (fun () ->
+    let rope = Leaf("ab", 0, 2) in
+    let rope = (puts rope "c" 2) in
+    assert( (length rope) == 3 );
+    assert( (getc rope (0)) == Char.code 'a' );
+    assert( (getc rope (1)) == Char.code 'b' );
+    assert( (getc rope (2)) == Char.code 'c' );
+  );
+
+  (* is_bol() tests *)
+  test "is_bol : should return true if pos is 0" (fun () ->
+    let rope = Leaf("abc", 0, 3) in
+    assert( is_bol rope 0 );
+  );
+  test "is_bol : should return true if pos is first char of line" (fun () ->
+    let rope = Leaf("\nabc", 0, 3) in
+    assert( is_bol rope 1 );
+  );
+  test "is_bol : should return false if pos is not first char of line" (fun () ->
+    let rope = Leaf("\nabc", 0, 3) in
+    assert( (is_bol rope 2) == false );
+  );
+  test "is_bol : should return false if previous char is not \n" (fun () ->
+    let rope = Leaf("\rabc", 0, 3) in
+    assert( (is_bol rope 1) == false );
+  );
+
+  (* is_eol() tests *)
+  test "is_eol : should return true if pos is Rope.last" (fun () ->
+    let rope = Leaf("abc", 0, 3) in
+    assert( is_eol rope 2 );
+  );
+  test "is_eol : should return true if pos is last char of line with \n ending" (fun () ->
+    let rope = Leaf("abc\n", 0, 4) in
+    assert( is_eol rope 2 );
+  );
+  test "is_eol : should return true if pos is last char of line with \r\n ending" (fun () ->
+    let rope = Leaf("abc\r\n", 0, 5) in
+    assert( is_eol rope 2 );
+  );
+  test "is_eol : should return false if pos is not last char of line" (fun () ->
+    let rope = Leaf("abcd\n", 0, 5) in
+    assert( (is_eol rope 2) == false );
+  );
+  ()
+
+(*
+
+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_find(Buf* buf, int dir, size_t* beg, size_t* end);
+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_getcol(Buf* buf, size_t pos);
+size_t buf_setcol(Buf* buf, size_t pos, size_t col);
+
+*)