Adding basic search to the text editor
This commit is contained in:
parent
8e05690ef3
commit
4a62774a57
3 changed files with 131 additions and 15 deletions
|
|
@ -160,6 +160,15 @@ find : (a \ Bool) \ List a \ Maybe a = f list \ list
|
|||
| True \ Some x
|
||||
| False \ find f xs);
|
||||
|
||||
findAll = query lines \
|
||||
mapWithIndex (line row \
|
||||
findInLine = col \
|
||||
strIndexOf query line col
|
||||
| None \ []
|
||||
| Some i \ [{ row = row, col = i }, ...findInLine (i + 1)];
|
||||
findInLine 0
|
||||
) lines ~ flatten;
|
||||
|
||||
flatten : List (List a) \ List a = lists \ fold cat [] lists;
|
||||
|
||||
and : Bool \ Bool \ Bool = x y \ x
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
@textEditor
|
||||
|
||||
textEditorBuffers = [];
|
||||
|
||||
textEditor = name \
|
||||
# defaults = {};
|
||||
# c = { ...defaults, ...config };
|
||||
|
|
@ -12,13 +10,6 @@ textEditor = name \
|
|||
charGap = 2;
|
||||
lineH = charH * scale + lineGap;
|
||||
|
||||
buffersKey = "textEditorBuffers";
|
||||
|
||||
# load from staging buffers if it exists there. if not, load from source
|
||||
# source = getAt [buffersKey, name]
|
||||
# | None \ getSource name
|
||||
# | Some v \ v;
|
||||
|
||||
source = getModuleSource name
|
||||
| Some s \ s
|
||||
| None \ getSource name;
|
||||
|
|
@ -251,6 +242,25 @@ textEditor = name \
|
|||
newState = clampCursor state.{ cursorCol = state.cursorCol + 1 };
|
||||
{ state = newState, emit = [] };
|
||||
|
||||
findNext = query lines row col \
|
||||
rest = strIndexOf query (nth row lines ~ unwrapOr "") (col + 1);
|
||||
rest
|
||||
| Some c \ { row = row, col = c }
|
||||
| None \ (
|
||||
findInLines = r \
|
||||
r >= len lines
|
||||
| True \ findInLines 0 # wrap to top
|
||||
| False \ (r == row
|
||||
| True \ (strIndexOf query (nth row lines ~ unwrapOr "") 0
|
||||
| Some c \ { row = row, col = c }
|
||||
| None \ { row = row, col = col }) # no match
|
||||
| False \ (strIndexOf query (nth r lines ~ unwrapOr "") 0
|
||||
| Some c \ { row = r, col = c }
|
||||
| None \ findInLines (r + 1)));
|
||||
findInLines (row + 1));
|
||||
|
||||
# TODO: findPrev
|
||||
|
||||
{
|
||||
view = ctx \
|
||||
|
||||
|
|
@ -273,6 +283,62 @@ textEditor = name \
|
|||
withScroll = result \
|
||||
{ state = autoScroll result.state, emit = result.emit };
|
||||
|
||||
# search stuff
|
||||
initSearch = state \
|
||||
newState = state.{
|
||||
mode = Search,
|
||||
searchQuery = "",
|
||||
savedCursorCol = state.cursorCol,
|
||||
savedCursorRow = state.cursorRow,
|
||||
};
|
||||
|
||||
{ state = newState, emit = [] };
|
||||
|
||||
cancelSearch = state \
|
||||
newState = state.{
|
||||
mode = Normal,
|
||||
searchQuery = "",
|
||||
cursorCol = state.savedCursorCol,
|
||||
cursorRow = state.savedCursorRow,
|
||||
};
|
||||
|
||||
{ state = newState, emit = [] };
|
||||
|
||||
updateSearchQuery = query state \
|
||||
next = findNext query state.lines state.cursorRow state.cursorCol;
|
||||
newState = autoScroll state.{
|
||||
searchQuery = query,
|
||||
cursorCol = next.col,
|
||||
cursorRow = next.row,
|
||||
};
|
||||
{ state = newState, emit = [] };
|
||||
|
||||
backspaceSearch = state \
|
||||
updateSearchQuery (slice state.searchQuery 0 (len state.searchQuery - 1)) state;
|
||||
|
||||
addCharToSearchQuery = char state \
|
||||
updateSearchQuery (state.searchQuery & char) state;
|
||||
|
||||
endSearch = state \
|
||||
# next = findNext state.searchQuery state.lines state.cursorRow state.cursorCol;
|
||||
newState = autoScroll state.{
|
||||
mode = Normal,
|
||||
# cursorCol = next.col,
|
||||
# cursorRow = next.row,
|
||||
};
|
||||
|
||||
{ state = newState, emit = [] };
|
||||
|
||||
nextSearch = state \
|
||||
next = findNext state.searchQuery state.lines state.cursorRow state.cursorCol;
|
||||
newState = autoScroll state.{
|
||||
mode = Normal,
|
||||
cursorCol = next.col,
|
||||
cursorRow = next.row,
|
||||
};
|
||||
|
||||
{ state = newState, emit = [] };
|
||||
|
||||
scrollHalfUp = state ctx \ (
|
||||
diff = floor ((ctx.h / 2) / lineH);
|
||||
newRow = state.cursorRow - diff;
|
||||
|
|
@ -295,19 +361,30 @@ textEditor = name \
|
|||
key = "textEditor-" & name,
|
||||
|
||||
init = {
|
||||
mode = Normal, # Normal | Insert | Visual | Search
|
||||
|
||||
lines = lines,
|
||||
cursorRow = 0,
|
||||
cursorCol = 0,
|
||||
scrollX = 0,
|
||||
scrollY = 0,
|
||||
|
||||
pending = None, # Some "d" | Some "g" | etc.
|
||||
lastAction = None, # Some { operator, motion },
|
||||
undoStack = [],
|
||||
redoStack = [],
|
||||
mode = Normal, # Normal | Insert | Visual
|
||||
pending = None, # Some "d" | Some "g" | etc.
|
||||
lastAction = None, # Some { operator, motion }
|
||||
|
||||
searchQuery = "",
|
||||
searchIndex = 0,
|
||||
},
|
||||
|
||||
update = state event \ state.mode
|
||||
| Search \ (event
|
||||
| Key { key = "Escape" } \ cancelSearch state
|
||||
| Key { key = "Enter" } \ endSearch state
|
||||
| Key { key = "Backspace" } \ backspaceSearch state
|
||||
| Key { key = k, printable = True } \ addCharToSearchQuery k state
|
||||
| _ \ { state = state , emit = [] })
|
||||
| Insert \ (event
|
||||
| Key { key = "Escape" } \ escape state
|
||||
| Key { key = "Control" } \ escape state
|
||||
|
|
@ -352,8 +429,13 @@ textEditor = name \
|
|||
| _ \ { state = state.{ pending = Some "g" }, emit = [] })
|
||||
| Key { key = "G" } \ handleMotion LastLine state
|
||||
| Key { key = "." } \ (state.lastAction
|
||||
| None \ { state = state, emit = [] }
|
||||
| Some action \ applyOperator action.operator action.motion state)
|
||||
| None \ { state = state, emit = [] }
|
||||
| Some action \ applyOperator action.operator action.motion state)
|
||||
# Search
|
||||
| Key { key = "/" } \ initSearch state
|
||||
| Key { key = "n" } \ nextSearch state
|
||||
| Key { key = "N" } \ prevSearch state
|
||||
|
||||
| Key { key = "W", ctrl = True, shift = True } \ write state
|
||||
| Key { key = "A", ctrl = True, shift = True } \ apply state
|
||||
# any other key or event
|
||||
|
|
@ -374,6 +456,22 @@ textEditor = name \
|
|||
totalWidth = maxLineLen * charW * scale + maxLineLen * charGap;
|
||||
totalHeight = len state.lines * lineH;
|
||||
|
||||
highlights = state.searchQuery == ""
|
||||
| True \ []
|
||||
| False \ findAll state.searchQuery state.lines;
|
||||
|
||||
highlightsUi = map (c \
|
||||
ui.positioned {
|
||||
x = c.col * charW * scale + charGap * c.col,
|
||||
y = c.row * lineH,
|
||||
child = ui.rect {
|
||||
w = (len state.searchQuery) * charW * scale + charGap * (len state.searchQuery - 1),
|
||||
h = charH * scale,
|
||||
color = "rgba(255,200,0,0.5)"
|
||||
}
|
||||
}
|
||||
) highlights;
|
||||
|
||||
# buffer = map (l \ text l) state.lines;
|
||||
# only render visible lines
|
||||
startLine = max 0 (floor (state.scrollY / lineH));
|
||||
|
|
@ -399,7 +497,8 @@ textEditor = name \
|
|||
child = ui.stack {
|
||||
children = [
|
||||
...buffer,
|
||||
cursor
|
||||
cursor,
|
||||
...highlightsUi
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,14 @@ export const _rt = {
|
|||
return String(value);
|
||||
},
|
||||
chars: (s: string) => s.split(''),
|
||||
strIndexOf: (needle: string) => (haystack: string) => (start: number) => {
|
||||
const i = haystack.indexOf(needle, start);
|
||||
return i === -1 ? { _tag: 'None' } : { _tag: 'Some', _0: i };
|
||||
},
|
||||
strLastIndexOf: (needle: string) => (haystack: string) => {
|
||||
const i = haystack.lastIndexOf(needle);
|
||||
return i === -1 ? { _tag: 'None' } : { _tag: 'Some', _0: i };
|
||||
},
|
||||
isWordChar: (s: string) => ({ _tag: /^\w$/.test(s) ? 'True' : 'False' }),
|
||||
// join: (delim: string) => (xs: string[]) => xs.join(delim),
|
||||
split: (delim: string) => (xs: string) => xs.split(delim),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue