feat: implement base autocomplete implementation for codemirror along with preRequest autocompletion
This commit is contained in:
committed by
liyasthomas
parent
dc5f52cc0d
commit
b9fc0175e7
@@ -8,6 +8,7 @@ import "codemirror/mode/javascript/javascript"
|
||||
import { ref, watch } from "@nuxtjs/composition-api"
|
||||
import { useCodemirror } from "~/helpers/editor/codemirror"
|
||||
import { LinterDefinition } from "~/helpers/editor/linting/linter"
|
||||
import { Completer } from "~/helpers/editor/completion"
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
@@ -16,11 +17,13 @@ const props = withDefaults(
|
||||
placeholder?: string
|
||||
wrap?: boolean
|
||||
linter: LinterDefinition | null
|
||||
completer: Completer | null
|
||||
}>(),
|
||||
{
|
||||
placeholder: "",
|
||||
wrap: true,
|
||||
linter: null as any,
|
||||
completer: null as any,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -45,5 +48,6 @@ useCodemirror(editor, value, {
|
||||
lineWrapping: props.wrap,
|
||||
},
|
||||
linter: props.linter,
|
||||
completer: props.completer,
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -7,6 +7,7 @@ import "codemirror/theme/3024-night.css"
|
||||
import "codemirror/lib/codemirror.css"
|
||||
import "codemirror/addon/lint/lint.css"
|
||||
import "codemirror/addon/dialog/dialog.css"
|
||||
import "codemirror/addon/hint/show-hint.css"
|
||||
|
||||
import "codemirror/addon/fold/foldgutter.css"
|
||||
import "codemirror/addon/fold/foldgutter"
|
||||
@@ -15,6 +16,7 @@ import "codemirror/addon/fold/comment-fold"
|
||||
import "codemirror/addon/fold/indent-fold"
|
||||
import "codemirror/addon/display/autorefresh"
|
||||
import "codemirror/addon/lint/lint"
|
||||
import "codemirror/addon/hint/show-hint"
|
||||
import "codemirror/addon/display/placeholder"
|
||||
import "codemirror/addon/edit/closebrackets"
|
||||
import "codemirror/addon/search/search"
|
||||
@@ -24,10 +26,12 @@ import "codemirror/addon/dialog/dialog"
|
||||
|
||||
import { watch, onMounted, ref, Ref, useContext } from "@nuxtjs/composition-api"
|
||||
import { LinterDefinition } from "./linting/linter"
|
||||
import { Completer } from "./completion"
|
||||
|
||||
type CodeMirrorOptions = {
|
||||
extendedEditorConfig: Omit<CodeMirror.EditorConfiguration, "value">
|
||||
linter: LinterDefinition | null
|
||||
completer: Completer | null
|
||||
}
|
||||
|
||||
const DEFAULT_EDITOR_CONFIG: CodeMirror.EditorConfiguration = {
|
||||
@@ -76,6 +80,31 @@ export function useCodemirror(
|
||||
}
|
||||
}
|
||||
|
||||
const updateCompleterConfig = () => {
|
||||
if (options.completer) {
|
||||
cm.value?.setOption("hintOptions", {
|
||||
completeSingle: false,
|
||||
hint: async (editor: CodeMirror.Editor) => {
|
||||
const pos = editor.getCursor()
|
||||
const text = editor.getValue()
|
||||
|
||||
const result = await options.completer!(text, pos)
|
||||
|
||||
console.log("complete!")
|
||||
console.log(result)
|
||||
|
||||
return <CodeMirror.Hints>{
|
||||
from: result.start,
|
||||
to: result.end,
|
||||
list: result.completions
|
||||
.sort((a, b) => a.score - b.score)
|
||||
.map((x) => x.text),
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Boot-up CodeMirror, set the value and listeners
|
||||
onMounted(() => {
|
||||
cm.value = CodeMirror(el.value!, DEFAULT_EDITOR_CONFIG)
|
||||
@@ -83,6 +112,7 @@ export function useCodemirror(
|
||||
setTheme()
|
||||
updateEditorConfig()
|
||||
updateLinterConfig()
|
||||
updateCompleterConfig()
|
||||
|
||||
cm.value.on("change", (instance) => {
|
||||
// External update propagation (via watchers) should be ignored
|
||||
@@ -90,6 +120,13 @@ export function useCodemirror(
|
||||
value.value = instance.getValue()
|
||||
}
|
||||
})
|
||||
|
||||
/* TODO: Show autocomplete on typing (this is just for testing) */
|
||||
cm.value.on("keyup", (instance, event) => {
|
||||
if (!instance.state.completionActive && event.key !== "Enter") {
|
||||
instance.showHint()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const setTheme = () => {
|
||||
@@ -120,6 +157,7 @@ export function useCodemirror(
|
||||
deep: true,
|
||||
})
|
||||
watch(() => options.linter, updateLinterConfig, { immediate: true })
|
||||
watch(() => options.completer, updateCompleterConfig, { immediate: true })
|
||||
|
||||
// Watch value updates
|
||||
watch(value, (newVal) => {
|
||||
|
||||
33
helpers/editor/completion/index.ts
Normal file
33
helpers/editor/completion/index.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
export type CompletionEntry = {
|
||||
text: string
|
||||
meta: string
|
||||
score: number
|
||||
}
|
||||
|
||||
export type CompleterResult = {
|
||||
/**
|
||||
* List of completions to display
|
||||
*/
|
||||
completions: CompletionEntry[]
|
||||
/**
|
||||
* Start of the completion position
|
||||
* (on completion the start..end region is replaced)
|
||||
*/
|
||||
start: { line: number; ch: number }
|
||||
/**
|
||||
* End of the completion position
|
||||
* (on completion the start..end region is replaced)
|
||||
*/
|
||||
end: { line: number; ch: number }
|
||||
}
|
||||
|
||||
export type Completer = (
|
||||
/**
|
||||
* The contents of the editor
|
||||
*/
|
||||
text: string,
|
||||
/**
|
||||
* Position where the completer is fired
|
||||
*/
|
||||
completePos: { line: number; ch: number }
|
||||
) => Promise<CompleterResult>
|
||||
30
helpers/editor/completion/preRequest.ts
Normal file
30
helpers/editor/completion/preRequest.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { convertIndexToLineCh } from "../utils"
|
||||
import { Completer, CompletionEntry } from "."
|
||||
import { getPreRequestScriptCompletions } from "~/helpers/tern"
|
||||
|
||||
const completer: Completer = async (text, completePos) => {
|
||||
const results = await getPreRequestScriptCompletions(
|
||||
text,
|
||||
completePos.line,
|
||||
completePos.ch
|
||||
)
|
||||
|
||||
const start = convertIndexToLineCh(text, results.start)
|
||||
const end = convertIndexToLineCh(text, results.end)
|
||||
|
||||
const completions = results.completions.map((completion: any, i: number) => {
|
||||
return <CompletionEntry>{
|
||||
text: completion.name,
|
||||
meta: completion.isKeyword ? "keyword" : completion.type,
|
||||
score: results.completions.length - i,
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
start,
|
||||
end,
|
||||
completions,
|
||||
}
|
||||
}
|
||||
|
||||
export default completer
|
||||
Reference in New Issue
Block a user