aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorHsieh Chin Fan <pham@topo.tw>2024-09-13 18:52:45 +0800
committerHsieh Chin Fan <pham@topo.tw>2024-09-13 18:59:14 +0800
commite8a94e5e43a306753b99615554e76a0815df090e (patch)
tree31941c5c69541225b14734a17084ed06cd3d76a7 /src
parentf1f5462fadd410dbbb6c284481b6ca7219313e64 (diff)
fix: Logic about suggestions
* Switch to event 'onCursorActivity' for suggestions * Show suggestion about Renderer without case sensitive
Diffstat (limited to 'src')
-rw-r--r--src/editor.mjs59
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 {{{
170const insideCodeblockForMap = (token) => 170const 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 {{{
174const getLineWithRenderer = (anchor) => { 177const 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 {{{
267const getSuggestions = (anchor) => { 269const 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
399cm.on("beforeSelectionChange", (_, obj) => { 410cm.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});