123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 |
- import { watch, Ref } from "@nuxtjs/composition-api"
- import { Compartment } from "@codemirror/state"
- import { hoverTooltip } from "@codemirror/tooltip"
- import {
- Decoration,
- EditorView,
- MatchDecorator,
- ViewPlugin,
- } from "@codemirror/view"
- import * as E from "fp-ts/Either"
- import { HoppRESTVar, parseTemplateStringE } from "@hoppscotch/data"
- const HOPP_ENVIRONMENT_REGEX = /({{\w+}})/g
- const HOPP_ENV_HIGHLIGHT =
- "cursor-help transition rounded px-1 focus:outline-none mx-0.5 env-highlight"
- const HOPP_ENV_HIGHLIGHT_FOUND =
- "bg-accentDark text-accentContrast hover:bg-accent"
- const HOPP_ENV_HIGHLIGHT_NOT_FOUND =
- "bg-red-500 text-accentContrast hover:bg-red-600"
- const cursorTooltipField = (aggregateEnvs: HoppRESTVar[]) =>
- hoverTooltip(
- (view, pos, side) => {
- const { from, to, text } = view.state.doc.lineAt(pos)
- // TODO: When Codemirror 6 allows this to work (not make the
- // popups appear half of the time) use this implementation
- // const wordSelection = view.state.wordAt(pos)
- // if (!wordSelection) return null
- // const word = view.state.doc.sliceString(
- // wordSelection.from - 2,
- // wordSelection.to + 2
- // )
- // if (!HOPP_ENVIRONMENT_REGEX.test(word)) return null
- // Tracking the start and the end of the words
- let start = pos
- let end = pos
- while (start > from && /\w/.test(text[start - from - 1])) start--
- while (end < to && /\w/.test(text[end - from])) end++
- if (
- (start === pos && side < 0) ||
- (end === pos && side > 0) ||
- !HOPP_ENVIRONMENT_REGEX.test(
- text.slice(start - from - 2, end - from + 2)
- )
- )
- return null
- const envValue =
- aggregateEnvs.find(
- (env) => env.key === text.slice(start - from, end - from)
- // env.key === word.slice(wordSelection.from + 2, wordSelection.to - 2)
- )?.value ?? "not found"
- const result = parseTemplateStringE(envValue, aggregateEnvs)
- const finalEnv = E.isLeft(result) ? "error" : result.right
- return {
- pos: start,
- end: to,
- above: true,
- arrow: true,
- create() {
- const dom = document.createElement("span")
- const xmp = document.createElement("xmp")
- xmp.textContent = finalEnv
- dom.appendChild(xmp)
- dom.className = "tooltip-theme"
- return { dom }
- },
- }
- },
- // HACK: This is a hack to fix hover tooltip not coming half of the time
- // https://github.com/codemirror/tooltip/blob/765c463fc1d5afcc3ec93cee47d72606bed27e1d/src/tooltip.ts#L622
- // Still doesn't fix the not showing up some of the time issue, but this is atleast more consistent
- { hoverTime: 1 } as any
- )
- function checkEnv(env: string, aggregateEnvs: HoppRESTVar[]) {
- const className = aggregateEnvs.find(
- (k: { key: string }) => k.key === env.slice(2, -2)
- )
- ? HOPP_ENV_HIGHLIGHT_FOUND
- : HOPP_ENV_HIGHLIGHT_NOT_FOUND
- return Decoration.mark({
- class: `${HOPP_ENV_HIGHLIGHT} ${className}`,
- })
- }
- const getMatchDecorator = (aggregateEnvs: HoppRESTVar[]) =>
- new MatchDecorator({
- regexp: HOPP_ENVIRONMENT_REGEX,
- decoration: (m) => checkEnv(m[0], aggregateEnvs),
- })
- export const environmentHighlightStyle = (aggregateEnvs: HoppRESTVar[]) => {
- const decorator = getMatchDecorator(aggregateEnvs)
- return ViewPlugin.define(
- (view) => ({
- decorations: decorator.createDeco(view),
- update(u) {
- this.decorations = decorator.updateDeco(u, this.decorations)
- },
- }),
- {
- decorations: (v) => v.decorations,
- }
- )
- }
- export class HoppReactiveVarPlugin {
- private compartment = new Compartment()
- private envs: HoppRESTVar[] = []
- constructor(
- envsRef: Ref<HoppRESTVar[]>,
- private editorView: Ref<EditorView | undefined>
- ) {
- watch(
- envsRef,
- (envs) => {
- this.envs = envs
- this.editorView.value?.dispatch({
- effects: this.compartment.reconfigure([
- cursorTooltipField(this.envs),
- environmentHighlightStyle(this.envs),
- ]),
- })
- },
- { immediate: true }
- )
- }
- get extension() {
- return this.compartment.of([
- cursorTooltipField(this.envs),
- environmentHighlightStyle(this.envs),
- ])
- }
- }
|