|
@@ -92,7 +92,7 @@ begin :: proc(s: ^State, id: u64, builder: ^strings.Builder) {
|
|
end(s)
|
|
end(s)
|
|
}
|
|
}
|
|
s.id = id
|
|
s.id = id
|
|
- s.selection = {len(builder.buf), 0}
|
|
|
|
|
|
+ s.selection = {len(builder.buf, 0}
|
|
s.builder = builder
|
|
s.builder = builder
|
|
update_time(s)
|
|
update_time(s)
|
|
undo_clear(s, &s.undo)
|
|
undo_clear(s, &s.undo)
|
|
@@ -137,6 +137,9 @@ clear_all :: proc(s: ^State) -> (cleared: bool) {
|
|
|
|
|
|
// push current text state to the wanted undo|redo stack
|
|
// push current text state to the wanted undo|redo stack
|
|
undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator_Error {
|
|
undo_state_push :: proc(s: ^State, undo: ^[dynamic]^Undo_State) -> mem.Allocator_Error {
|
|
|
|
+ if s.builder != nil {
|
|
|
|
+ return nil
|
|
|
|
+ }
|
|
text := string(s.builder.buf[:])
|
|
text := string(s.builder.buf[:])
|
|
item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator) or_return)
|
|
item := (^Undo_State)(mem.alloc(size_of(Undo_State) + len(text), align_of(Undo_State), s.undo_text_allocator) or_return)
|
|
item.selection = s.selection
|
|
item.selection = s.selection
|
|
@@ -154,7 +157,7 @@ undo :: proc(s: ^State, undo, redo: ^[dynamic]^Undo_State) {
|
|
undo_state_push(s, redo)
|
|
undo_state_push(s, redo)
|
|
item := pop(undo)
|
|
item := pop(undo)
|
|
s.selection = item.selection
|
|
s.selection = item.selection
|
|
- #no_bounds_check {
|
|
|
|
|
|
+ #no_bounds_check if s.builder != nil {
|
|
strings.builder_reset(s.builder)
|
|
strings.builder_reset(s.builder)
|
|
strings.write_string(s.builder, string(item.text[:item.len]))
|
|
strings.write_string(s.builder, string(item.text[:item.len]))
|
|
}
|
|
}
|
|
@@ -224,13 +227,17 @@ input_rune :: proc(s: ^State, r: rune) {
|
|
// insert a single rune into the edit state - deletes the current selection
|
|
// insert a single rune into the edit state - deletes the current selection
|
|
insert :: proc(s: ^State, at: int, text: string) {
|
|
insert :: proc(s: ^State, at: int, text: string) {
|
|
undo_check(s)
|
|
undo_check(s)
|
|
- inject_at(&s.builder.buf, at, text)
|
|
|
|
|
|
+ if s.builder != nil {
|
|
|
|
+ inject_at(&s.builder.buf, at, text)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// remove the wanted range withing, usually the selection within byte indices
|
|
// remove the wanted range withing, usually the selection within byte indices
|
|
remove :: proc(s: ^State, lo, hi: int) {
|
|
remove :: proc(s: ^State, lo, hi: int) {
|
|
undo_check(s)
|
|
undo_check(s)
|
|
- remove_range(&s.builder.buf, lo, hi)
|
|
|
|
|
|
+ if s.builder != nil {
|
|
|
|
+ remove_range(&s.builder.buf, lo, hi)
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
// true if selection head and tail dont match and form a selection of multiple characters
|
|
// true if selection head and tail dont match and form a selection of multiple characters
|
|
@@ -244,8 +251,8 @@ has_selection :: proc(s: ^State) -> bool {
|
|
sorted_selection :: proc(s: ^State) -> (lo, hi: int) {
|
|
sorted_selection :: proc(s: ^State) -> (lo, hi: int) {
|
|
lo = min(s.selection[0], s.selection[1])
|
|
lo = min(s.selection[0], s.selection[1])
|
|
hi = max(s.selection[0], s.selection[1])
|
|
hi = max(s.selection[0], s.selection[1])
|
|
- lo = clamp(lo, 0, len(s.builder.buf))
|
|
|
|
- hi = clamp(hi, 0, len(s.builder.buf))
|
|
|
|
|
|
+ lo = clamp(lo, 0, len(s.builder.buf) if s.builder != nil else 0)
|
|
|
|
+ hi = clamp(hi, 0, len(s.builder.buf) if s.builder != nil else 0)
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
@@ -265,7 +272,10 @@ translate_position :: proc(s: ^State, t: Translation) -> int {
|
|
return b == ' ' || b == '\t' || b == '\n'
|
|
return b == ' ' || b == '\t' || b == '\n'
|
|
}
|
|
}
|
|
|
|
|
|
- buf := s.builder.buf[:]
|
|
|
|
|
|
+ buf: []byte
|
|
|
|
+ if s.builder != nil {
|
|
|
|
+ buf = s.builder.buf[:]
|
|
|
|
+ }
|
|
pos := clamp(s.selection[0], 0, len(buf))
|
|
pos := clamp(s.selection[0], 0, len(buf))
|
|
|
|
|
|
switch t {
|
|
switch t {
|
|
@@ -352,7 +362,10 @@ delete_to :: proc(s: ^State, t: Translation) {
|
|
// return the currently selected text
|
|
// return the currently selected text
|
|
current_selected_text :: proc(s: ^State) -> string {
|
|
current_selected_text :: proc(s: ^State) -> string {
|
|
lo, hi := sorted_selection(s)
|
|
lo, hi := sorted_selection(s)
|
|
- return string(s.builder.buf[lo:hi])
|
|
|
|
|
|
+ if s.builder != nil {
|
|
|
|
+ return string(s.builder.buf[lo:hi])
|
|
|
|
+ }
|
|
|
|
+ return ""
|
|
}
|
|
}
|
|
|
|
|
|
// copy & delete the current selection when copy() succeeds
|
|
// copy & delete the current selection when copy() succeeds
|
|
@@ -431,7 +444,7 @@ perform_command :: proc(s: ^State, cmd: Command) {
|
|
case .Cut: cut(s)
|
|
case .Cut: cut(s)
|
|
case .Copy: copy(s)
|
|
case .Copy: copy(s)
|
|
case .Paste: paste(s)
|
|
case .Paste: paste(s)
|
|
- case .Select_All: s.selection = {len(s.builder.buf), 0}
|
|
|
|
|
|
+ case .Select_All: s.selection = {len(s.builder.buf) if s.builder != nil else 0, 0}
|
|
case .Backspace: delete_to(s, .Left)
|
|
case .Backspace: delete_to(s, .Left)
|
|
case .Delete: delete_to(s, .Right)
|
|
case .Delete: delete_to(s, .Right)
|
|
case .Delete_Word_Left: delete_to(s, .Word_Left)
|
|
case .Delete_Word_Left: delete_to(s, .Word_Left)
|