Skip to content

Commit

Permalink
refactor: improvements to completions
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Jan 4, 2024
1 parent 52ff050 commit 53192ce
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 17 deletions.
2 changes: 1 addition & 1 deletion language-configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
],
"folding": {
"markers": {
"start": "^\\s*(@((?!let|eval|assign|include|includeIf|inject|newError)[a-zA-Z._]+)(\\s{0,2}))(\\()",
"start": "^\\s*(@((?!let|eval|assign|include|includeIf|inject|newError|svg)[a-zA-Z._]+)(\\s{0,2}))(\\()",
"end": "^\\s*@end([a-zA-Z._]?)\\b"
}
},
Expand Down
6 changes: 3 additions & 3 deletions src/regexes.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/**
* Find all the views that are being used inside an Edge template
*/
export const edgeRegex = /(@include|@layout|@!?component)\(['"]([^'"]+)['"]/g
export const edgeRegex = /(@include|@!?component)\(['"]([^'"]+)['"]/g

/**
* Find all components as tags inside an Edge template
*/
export const edgeComponentsAsTagsRegex =
/^[ \t]*(@!?(?!include|set|can|unless|let|eval|inject|!component|if|elseif|vite|entryPointScripts|entryPointStyles|each|click|section|layout|component|slot|!section)(.+?))\(.*/gm
/^[ \t]*(@!?(?!include|includeIf|set|can|unless|svg|let|eval|inject|!component|if|elseif|else|vite|entryPointScripts|entryPointStyles|each|assign|debugger|component|slot|newError)(.+?))\(.*/gm

/**
* Find all the views that are being used inside a TS/Js file
Expand All @@ -24,7 +24,7 @@ export const viewsCompletionRegex = /(?<=@include\(['"]|@layout\(['"]|@!componen
* to suggest completions
*/
export const edgeComponentsAsTagsCompletionRegex =
/@!?(?!include|set|unless|let|eval|inject|!component|if|elseif|vite|entryPointScripts|entryPointStyles|each|click|section|layout|component|slot|!section)(.+)?\(?/g
/@!?(?!include|includeIf|set|can|unless|svg|let|eval|inject|!component|if|elseif|else|vite|entryPointScripts|entryPointStyles|each|assign|debugger|component|slot|newError)(.+)?\(?/g

/**
* Check if we are currently inside a view link and capture the user input to suggest completions
Expand Down
10 changes: 9 additions & 1 deletion src/template_indexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,15 @@ export class TemplateIndexer {
const name = disk === 'default' ? filename : `${disk}::${filename}`
const componentName = this.#componentFileNameToTagName(diskPath, path, disk)

return { path, name, disk, isComponent: !!componentName, componentName }
return {
path,
name,
disk,
isComponent: !!componentName,
componentName,
selfClosedInsertText: `${componentName}(\${1})`,
insertText: `${componentName}(\${1}) \n\t$0\n@end`,
}
})

return this.#templates
Expand Down
11 changes: 11 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ export interface Template {
*/
disk: string

/**
* Text to insert on completion
*/
insertText: string

/**
* Text to insert on completion for a self
* closed usage
*/
selfClosedInsertText: string

/**
* Whether the template is a component or not ( located in a components/ directory )
*/
Expand Down
12 changes: 12 additions & 0 deletions src/vscode/builtin_tags_completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ componentItem.documentation = new MarkdownString(
)
componentItem.detail = 'Render a component'

/**
* Self closing `@component`
*/
const selfClosingComponentItem = new CompletionItem('component', CompletionItemKind.Keyword)
selfClosingComponentItem.insertText = new SnippetString("component('${1:componentName}', { $2 })")
selfClosingComponentItem.documentation = new MarkdownString(
'Insert an @component statement\n\nhttps://edgejs.dev/docs/components/introduction'
)
selfClosingComponentItem.detail = 'Render a self closing component'

/**
* `@slot`
*/
Expand Down Expand Up @@ -211,3 +221,5 @@ export const builtinTags = [
layoutItem,
setItem,
]

export const builtinSelfClosingTags = [selfClosingComponentItem]
42 changes: 31 additions & 11 deletions src/vscode/providers/edge_completions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { CompletionItemKind, Position, Range } from 'vscode'
import { SuperCompletionItem } from '../wrappers'
import { IndexerManager } from '../indexer_manager'
import { edgeComponentsAsTagsCompletionRegex, viewsCompletionRegex } from '../../regexes'
import { SuperCompletionItem } from '../wrappers'
import { builtinTags } from '../builtin_tags_completion'
import { builtinSelfClosingTags, builtinTags } from '../builtin_tags_completion'
import type { CompletionItem, CompletionItemProvider, TextDocument } from 'vscode'

/**
Expand All @@ -28,9 +28,15 @@ export class EdgeCompletionProvider implements CompletionItemProvider {
* Check if we are within a tag completion context and return builtin tag suggestions if so
*/
const range = new Range(new Position(pos.line, 0), pos)
const tagMatch = doc.getText(range).match(/\s*@(\w*)$/)
const text = doc.getText(range)
const tagMatch = text.match(/\s*@(\w*)$/)
const selfClosingMatch = text.match(/\s*@!(\w*)$/)
if (tagMatch) {
completionItems = builtinTags.filter((tag) => tag.label.toString().startsWith(tagMatch[1]!))
} else if (selfClosingMatch) {
completionItems = builtinSelfClosingTags.filter((tag) =>
tag.label.toString().startsWith(selfClosingMatch[1]!)
)
}

/**
Expand All @@ -39,15 +45,29 @@ export class EdgeCompletionProvider implements CompletionItemProvider {
const componentAsTagRange = doc.getWordRangeAtPosition(pos, edgeComponentsAsTagsCompletionRegex)
if (componentAsTagRange) {
const text = doc.getText(componentAsTagRange)
const items = indexer?.searchComponent(text)?.map(({ componentName, disk }) => {
return new SuperCompletionItem({
label: componentName!,
detail: disk,
kind: CompletionItemKind.Constructor,
indexer
?.searchComponent(text)
?.forEach(({ componentName, selfClosedInsertText, insertText, disk }) => {
if (selfClosingMatch) {
completionItems.push(
new SuperCompletionItem({
label: `!${componentName!}`,
detail: disk,
insertText: selfClosedInsertText,
kind: CompletionItemKind.Function,
})
)
} else {
completionItems.push(
new SuperCompletionItem({
label: componentName!,
detail: disk,
insertText,
kind: CompletionItemKind.Function,
})
)
}
})
})

completionItems.push(...(items ?? []))
}

return completionItems
Expand Down
6 changes: 5 additions & 1 deletion src/vscode/wrappers.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { CompletionItem, MarkdownString } from 'vscode'
import { CompletionItem, MarkdownString, SnippetString } from 'vscode'
import type { CompletionItemKind, Range } from 'vscode'

export class SuperCompletionItem extends CompletionItem {
constructor(options: {
label: string
insertText?: string
documentation?: string
detail?: string
kind?: CompletionItemKind
range?: Range
}) {
super(options.label, options.kind)
this.detail = options.detail
if (options.insertText) {
this.insertText = new SnippetString(options.insertText)
}
this.documentation = new MarkdownString(options.documentation as string)
this.range = options.range
}
Expand Down

0 comments on commit 53192ce

Please sign in to comment.