diff options
author | Hsieh Chin Fan <pham@topo.tw> | 2024-09-13 18:52:45 +0800 |
---|---|---|
committer | Hsieh Chin Fan <pham@topo.tw> | 2024-09-13 18:59:14 +0800 |
commit | e8a94e5e43a306753b99615554e76a0815df090e (patch) | |
tree | 31941c5c69541225b14734a17084ed06cd3d76a7 /src/editor.mjs | |
parent | f1f5462fadd410dbbb6c284481b6ca7219313e64 (diff) |
fix: Logic about suggestions
* Switch to event 'onCursorActivity' for suggestions
* Show suggestion about Renderer without case sensitive
Diffstat (limited to 'src/editor.mjs')
-rw-r--r-- | src/editor.mjs | 59 |
1 files changed, 35 insertions, 24 deletions
diff --git a/src/editor.mjs b/src/editor.mjs index d1b4ba1..bf59e47 100644 --- a/src/editor.mjs +++ b/src/editor.mjs | |||
@@ -166,21 +166,24 @@ fetch(defaultApply) | |||
166 | // return true | 166 | // return true |
167 | // } | 167 | // } |
168 | // }}} | 168 | // }}} |
169 | // FUNCTION Check if current token is inside code block {{{ | 169 | // FUNCTION: Check if current token is inside code block {{{ |
170 | const insideCodeblockForMap = (token) => | 170 | const insideCodeblockForMap = (anchor) => { |
171 | token.state.overlay.codeBlock && !token.string.match(/^````*/) | 171 | const token = cm.getTokenAt(anchor) |
172 | const result = token.state.overlay.codeBlock && !cm.getLine(anchor.line).match(/^````*/) | ||
173 | return result | ||
174 | } | ||
172 | // }}} | 175 | // }}} |
173 | // FUNCTION: Get renderer by cursor position in code block {{{ | 176 | // FUNCTION: Get renderer by cursor position in code block {{{ |
174 | const getLineWithRenderer = (anchor) => { | 177 | const getLineWithRenderer = (anchor) => { |
175 | const currentLine = anchor.line | 178 | const currentLine = anchor.line |
176 | const match = (line) => cm.getLine(line).match(/^use: /) | 179 | const match = (line) => cm.getLine(line).match(/^use: /) |
180 | |||
177 | if (match(currentLine)) return currentLine | 181 | if (match(currentLine)) return currentLine |
178 | 182 | ||
179 | const getToken = (line) => cm.getTokenAt({ line: line, ch: 1 }) | ||
180 | 183 | ||
181 | // Look backward/forward for pattern of used renderer: /use: .+/ | 184 | // Look backward/forward for pattern of used renderer: /use: .+/ |
182 | let ps = currentLine - 1 | 185 | let ps = currentLine - 1 |
183 | while (ps > 0 && insideCodeblockForMap(getToken(ps))) { | 186 | while (ps > 0 && insideCodeblockForMap(anchor)) { |
184 | if (match(ps)) { | 187 | if (match(ps)) { |
185 | return ps | 188 | return ps |
186 | } else if (cm.getLine(ps).match(/^---/)) { | 189 | } else if (cm.getLine(ps).match(/^---/)) { |
@@ -191,11 +194,10 @@ const getLineWithRenderer = (anchor) => { | |||
191 | } | 194 | } |
192 | 195 | ||
193 | let ns = currentLine + 1 | 196 | let ns = currentLine + 1 |
194 | while (insideCodeblockForMap(getToken(ns))) { | 197 | while (insideCodeblockForMap(anchor)) { |
195 | if (match(ns)) { | 198 | if (match(ns)) { |
196 | return ns | 199 | return ns |
197 | } else if (cm.getLine(ns).match(/^---/)) { | 200 | } else if (cm.getLine(ns).match(/^---/)) { |
198 | // If yaml doc separator is found | ||
199 | return null | 201 | return null |
200 | } | 202 | } |
201 | ns = ns + 1 | 203 | ns = ns + 1 |
@@ -265,18 +267,22 @@ const handleTypingInCodeBlock = (anchor) => { | |||
265 | // }}} | 267 | // }}} |
266 | // FUNCTION: get suggestions by current input {{{ | 268 | // FUNCTION: get suggestions by current input {{{ |
267 | const getSuggestions = (anchor) => { | 269 | const getSuggestions = (anchor) => { |
268 | const text = cm.getLine(anchor.line) | ||
269 | const markInputIsInvalid = () => cm.getDoc().markText( | ||
270 | { ...anchor, ch: 0 }, | ||
271 | { ...anchor, ch: -1 }, | ||
272 | { className: 'invalid-input' }, | ||
273 | ) | ||
274 | let suggestions = [] | 270 | let suggestions = [] |
271 | const text = cm.getLine(anchor.line) | ||
272 | const markInputIsInvalid = () => { | ||
273 | cm.getDoc().markText( | ||
274 | { ...anchor, ch: 0 }, | ||
275 | { ...anchor, ch: -1 }, | ||
276 | { className: 'invalid-input' }, | ||
277 | ) | ||
278 | } | ||
275 | 279 | ||
276 | // Check if "use: <renderer>" is set | 280 | // Check if "use: <renderer>" is set |
277 | const lineWithRenderer = getLineWithRenderer(anchor) | 281 | const lineWithRenderer = getLineWithRenderer(anchor) |
278 | const renderer = cm.getLine(lineWithRenderer).split(' ')[1] | 282 | const renderer = lineWithRenderer |
279 | if (renderer) { | 283 | ? cm.getLine(lineWithRenderer).split(' ')[1] |
284 | : null | ||
285 | if (renderer && anchor.line !== lineWithRenderer) { | ||
280 | // Do not check properties | 286 | // Do not check properties |
281 | if (text.startsWith(' ')) return [] | 287 | if (text.startsWith(' ')) return [] |
282 | 288 | ||
@@ -288,10 +294,14 @@ const getSuggestions = (anchor) => { | |||
288 | import(rendererUrl) | 294 | import(rendererUrl) |
289 | .then(rendererModule => { | 295 | .then(rendererModule => { |
290 | rendererOptions[renderer] = rendererModule.default.validOptions | 296 | rendererOptions[renderer] = rendererModule.default.validOptions |
297 | const currentAnchor = cm.getCursor() | ||
298 | if (insideCodeblockForMap(currentAnchor)) { | ||
299 | handleTypingInCodeBlock(currentAnchor) | ||
300 | } | ||
291 | }) | 301 | }) |
292 | .catch(_ => { | 302 | .catch(_ => { |
293 | markInputIsInvalid(lineWithRenderer) | 303 | markInputIsInvalid(lineWithRenderer) |
294 | console.warn(`Fail to get valid options from renderer with URL ${rendererUrl}`) | 304 | console.warn(`Fail to get valid options from Renderer typed: ${renderer}`) |
295 | }) | 305 | }) |
296 | return [] | 306 | return [] |
297 | } | 307 | } |
@@ -336,10 +346,10 @@ const getSuggestions = (anchor) => { | |||
336 | const rendererSuggestions = Object.entries(defaultAliasesForRenderer.use) | 346 | const rendererSuggestions = Object.entries(defaultAliasesForRenderer.use) |
337 | .filter(([renderer,]) => { | 347 | .filter(([renderer,]) => { |
338 | const suggestion = `use: ${renderer}` | 348 | const suggestion = `use: ${renderer}` |
339 | const suggetionNoSpace = suggestion.replace(' ', '') | 349 | const suggestionPattern = suggestion.replace(' ', '').toLowerCase() |
340 | const textNoSpace = text.replace(' ', '') | 350 | const textPattern = text.replace(' ', '').toLowerCase() |
341 | return suggestion !== text && | 351 | return suggestion !== text && |
342 | (suggetionNoSpace.includes(textNoSpace)) | 352 | (suggestionPattern.includes(textPattern)) |
343 | }) | 353 | }) |
344 | .map(([renderer, info]) => | 354 | .map(([renderer, info]) => |
345 | new Suggestion({ | 355 | new Suggestion({ |
@@ -392,15 +402,16 @@ const addSuggestions = (anchor, suggestions) => { | |||
392 | const rect = suggestionsEle.getBoundingClientRect() | 402 | const rect = suggestionsEle.getBoundingClientRect() |
393 | suggestionsEle.style.maxWidth = `calc(${window.innerWidth}px - ${rect.x}px - 2rem)`; | 403 | suggestionsEle.style.maxWidth = `calc(${window.innerWidth}px - ${rect.x}px - 2rem)`; |
394 | suggestionsEle.style.display = 'block' | 404 | suggestionsEle.style.display = 'block' |
405 | suggestionsEle.style.transform = 'translate(2em, 1em)' | ||
395 | } | 406 | } |
396 | // }}} | 407 | // }}} |
397 | // EVENT: suggests for current selection {{{ | 408 | // EVENT: Suggests for current selection {{{ |
398 | // FIXME Dont show suggestion when selecting multiple chars | 409 | // FIXME Dont show suggestion when selecting multiple chars |
399 | cm.on("beforeSelectionChange", (_, obj) => { | 410 | cm.on("cursorActivity", (_) => { |
400 | const anchor = (obj.ranges[0].anchor) | 411 | suggestionsEle.style.display = 'none' |
401 | const token = cm.getTokenAt(anchor) | 412 | const anchor = cm.getCursor() |
402 | 413 | ||
403 | if (insideCodeblockForMap(token)) { | 414 | if (insideCodeblockForMap(anchor)) { |
404 | handleTypingInCodeBlock(anchor) | 415 | handleTypingInCodeBlock(anchor) |
405 | } | 416 | } |
406 | }); | 417 | }); |