about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2024-06-27 22:17:11 -0700
committerKartik K. Agaram <vc@akkartik.com>2024-06-27 22:29:22 -0700
commit5b99a64a73fe16787e7d77bcc1c75e5bc384c2b7 (patch)
tree2ef4838ec8ca1e3ba32e8e60a761b0fd263a380f
parent0f9cbbd96be44ef328e2cbe6dd62c8af7254dc65 (diff)
parent54addeb3b782125e7e0024347d6961efcbc4964c (diff)
downloadview.love-5b99a64a73fe16787e7d77bcc1c75e5bc384c2b7.tar.gz
Merge text.love
I'm going to pull some shared code into the same place as upstream
forks, just to reduce future merge conflicts.
-rw-r--r--edit.lua7
-rw-r--r--main.lua1
-rw-r--r--select.lua8
-rw-r--r--source_edit.lua4
-rw-r--r--source_text.lua28
-rw-r--r--text.lua28
-rw-r--r--undo.lua16
7 files changed, 55 insertions, 37 deletions
diff --git a/edit.lua b/edit.lua
index 8383a11..af04832 100644
--- a/edit.lua
+++ b/edit.lua
@@ -177,7 +177,7 @@ function edit.mouse_release(State, x,y, mouse_button)
 --?   print_and_log(('edit.mouse_release(%d,%d): cursor at %d,%d'):format(x,y, State.cursor1.line, State.cursor1.pos))
   State.mouse_down = nil
   if y < State.top then
-    State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+    State.cursor1 = deepcopy(State.screen_top1)
     edit.clean_up_mouse_press(State)
     return
   end
@@ -216,7 +216,7 @@ end
 
 function edit.mouse_wheel_move(State, dx,dy)
   if dy > 0 then
-    State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+    State.cursor1 = deepcopy(State.screen_top1)
     for i=1,math.floor(dy) do
       Text.up(State)
     end
@@ -258,6 +258,9 @@ function edit.keychord_press(State, chord, key)
       local len = utf8.len(State.search_term)
       local byte_offset = Text.offset(State.search_term, len)
       State.search_term = string.sub(State.search_term, 1, byte_offset-1)
+      State.cursor = deepcopy(State.search_backup.cursor)
+      State.screen_top = deepcopy(State.search_backup.screen_top)
+      Text.search_next(State)
     elseif chord == 'down' then
       State.cursor1.pos = State.cursor1.pos+1
       Text.search_next(State)
diff --git a/main.lua b/main.lua
index fca94b5..582f05a 100644
--- a/main.lua
+++ b/main.lua
@@ -48,6 +48,7 @@ function App.load()
       load_file_from_source_or_save_directory('text.lua')
         load_file_from_source_or_save_directory('search.lua')
         load_file_from_source_or_save_directory('select.lua')
+        load_file_from_source_or_save_directory('undo.lua')
       load_file_from_source_or_save_directory('text_tests.lua')
     load_file_from_source_or_save_directory('run_tests.lua')
   elseif Current_app == 'source' then
diff --git a/select.lua b/select.lua
index 2d0851a..018ddef 100644
--- a/select.lua
+++ b/select.lua
@@ -1,9 +1,8 @@
 -- helpers for selecting portions of text
 
--- Return any intersection of the region from State.selection1 to State.cursor1 (or
--- current mouse, if mouse is pressed; or recent mouse if mouse is pressed and
--- currently over a drawing) with the region between {line=line_index, pos=apos}
--- and {line=line_index, pos=bpos}.
+-- Return any intersection of the region from State.selection1 to
+-- State.cursor1 (or current mouse, if mouse is pressed) with the region
+-- between {line=line_index, pos=apos} and {line=line_index, pos=bpos}.
 -- apos must be less than bpos. However State.selection1 and State.cursor1 can be in any order.
 -- Result: positions spos,epos between apos,bpos.
 function Text.clip_selection(State, line_index, apos, bpos)
@@ -45,7 +44,6 @@ function Text.clip_selection(State, line_index, apos, bpos)
 end
 
 -- draw highlight for line corresponding to (lo,hi) given an approximate x,y and pos on the same screen line
--- Creates text objects every time, so use this sparingly.
 -- Returns some intermediate computation useful elsewhere.
 function Text.draw_highlight(State, line, x,y, pos, lo,hi)
   if lo then
diff --git a/source_edit.lua b/source_edit.lua
index 5351857..34e12c3 100644
--- a/source_edit.lua
+++ b/source_edit.lua
@@ -308,7 +308,7 @@ function edit.mouse_release(State, x,y, mouse_button)
   else
 --?     print_and_log('edit.mouse_release: no current drawing')
     if y < State.top then
-      State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+      State.cursor1 = deepcopy(State.screen_top1)
       edit.clean_up_mouse_press(State)
       return
     end
@@ -351,7 +351,7 @@ end
 
 function edit.mouse_wheel_move(State, dx,dy)
   if dy > 0 then
-    State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+    State.cursor1 = deepcopy(State.screen_top1)
     edit.put_cursor_on_next_text_line(State)
     for i=1,math.floor(dy) do
       Text.up(State)
diff --git a/source_text.lua b/source_text.lua
index 6e0c4f9..931dd00 100644
--- a/source_text.lua
+++ b/source_text.lua
@@ -338,12 +338,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'S-left' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.left(State)
   elseif chord == 'S-right' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.right(State)
   -- C- hotkeys reserved for drawings, so we'll use M-
@@ -355,12 +355,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'M-S-left' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.word_left(State)
   elseif chord == 'M-S-right' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.word_right(State)
   elseif chord == 'home' then
@@ -371,12 +371,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'S-home' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.start_of_line(State)
   elseif chord == 'S-end' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.end_of_line(State)
   elseif chord == 'up' then
@@ -387,12 +387,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'S-up' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.up(State)
   elseif chord == 'S-down' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.down(State)
   elseif chord == 'pageup' then
@@ -403,12 +403,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'S-pageup' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.pageup(State)
   elseif chord == 'S-pagedown' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.pagedown(State)
   end
@@ -425,7 +425,7 @@ end
 
 function Text.pageup(State)
   State.screen_top1 = Text.previous_screen_top1(State)
-  State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+  State.cursor1 = deepcopy(State.screen_top1)
   Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
   Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
 end
@@ -474,7 +474,7 @@ end
 
 function Text.pagedown(State)
   State.screen_top1 = Text.screen_bottom1(State)
-  State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+  State.cursor1 = deepcopy(State.screen_top1)
   Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
   Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
 end
@@ -594,7 +594,7 @@ end
 function Text.start_of_line(State)
   State.cursor1.pos = 1
   if Text.lt1(State.cursor1, State.screen_top1) then
-    State.screen_top1 = {line=State.cursor1.line, pos=State.cursor1.pos}  -- copy
+    State.screen_top1 = deepcopy(State.cursor1)
   end
 end
 
@@ -1103,7 +1103,7 @@ function Text.tweak_screen_top_and_cursor(State)
   -- make sure cursor is on screen
   local screen_bottom1 = Text.screen_bottom1(State)
   if Text.lt1(State.cursor1, State.screen_top1) then
-    State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+    State.cursor1 = deepcopy(State.screen_top1)
   elseif State.cursor1.line >= screen_bottom1.line then
     if Text.cursor_out_of_screen(State) then
       State.cursor1 = Text.final_text_loc_on_screen(State)
diff --git a/text.lua b/text.lua
index ec28509..f2f4d6e 100644
--- a/text.lua
+++ b/text.lua
@@ -146,12 +146,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'S-left' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.left(State)
   elseif chord == 'S-right' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.right(State)
   -- C- hotkeys reserved for drawings, so we'll use M-
@@ -163,12 +163,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'M-S-left' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.word_left(State)
   elseif chord == 'M-S-right' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.word_right(State)
   elseif chord == 'home' then
@@ -179,12 +179,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'S-home' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.start_of_line(State)
   elseif chord == 'S-end' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.end_of_line(State)
   elseif chord == 'up' then
@@ -195,12 +195,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'S-up' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.up(State)
   elseif chord == 'S-down' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.down(State)
   elseif chord == 'pageup' then
@@ -211,12 +211,12 @@ function Text.keychord_press(State, chord)
     State.selection1 = {}
   elseif chord == 'S-pageup' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.pageup(State)
   elseif chord == 'S-pagedown' then
     if State.selection1.line == nil then
-      State.selection1 = {line=State.cursor1.line, pos=State.cursor1.pos}
+      State.selection1 = deepcopy(State.cursor1)
     end
     Text.pagedown(State)
   end
@@ -224,7 +224,7 @@ end
 
 function Text.pageup(State)
   State.screen_top1 = Text.previous_screen_top1(State)
-  State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+  State.cursor1 = deepcopy(State.screen_top1)
   Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
   Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
 end
@@ -262,7 +262,7 @@ end
 
 function Text.pagedown(State)
   State.screen_top1 = Text.screen_bottom1(State)
-  State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+  State.cursor1 = deepcopy(State.screen_top1)
   Text.move_cursor_down_to_next_text_line_while_scrolling_again_if_necessary(State)
   Text.redraw_all(State)  -- if we're scrolling, reclaim all fragments to avoid memory leaks
 end
@@ -366,7 +366,7 @@ end
 function Text.start_of_line(State)
   State.cursor1.pos = 1
   if Text.lt1(State.cursor1, State.screen_top1) then
-    State.screen_top1 = {line=State.cursor1.line, pos=State.cursor1.pos}  -- copy
+    State.screen_top1 = deepcopy(State.cursor1)
   end
 end
 
@@ -806,7 +806,7 @@ function Text.tweak_screen_top_and_cursor(State)
   -- make sure cursor is on screen
   local screen_bottom1 = Text.screen_bottom1(State)
   if Text.lt1(State.cursor1, State.screen_top1) then
-    State.cursor1 = {line=State.screen_top1.line, pos=State.screen_top1.pos}
+    State.cursor1 = deepcopy(State.screen_top1)
   elseif State.cursor1.line >= screen_bottom1.line then
     if Text.cursor_out_of_screen(State) then
       State.cursor1 = Text.final_text_loc_on_screen(State)
diff --git a/undo.lua b/undo.lua
new file mode 100644
index 0000000..fcfdb6a
--- /dev/null
+++ b/undo.lua
@@ -0,0 +1,16 @@
+-- https://stackoverflow.com/questions/640642/how-do-you-copy-a-lua-table-by-value/26367080#26367080
+function deepcopy(obj, seen)
+  if type(obj) ~= 'table' then return obj end
+  if seen and seen[obj] then return seen[obj] end
+  local s = seen or {}
+  local result = setmetatable({}, getmetatable(obj))
+  s[obj] = result
+  for k,v in pairs(obj) do
+    result[deepcopy(k, s)] = deepcopy(v, s)
+  end
+  return result
+end
+
+function minmax(a, b)
+  return math.min(a,b), math.max(a,b)
+end