-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Blade Directive Completion (#10)
- Loading branch information
Showing
6 changed files
with
270 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
{ | ||
"@extends": "extends view layout", | ||
"@yield": "yield content section", | ||
"@section": "content section show", | ||
"@endsection": "content section", | ||
"@show": "content section show", | ||
"@include": "include view", | ||
"@if": "$loop->last", | ||
"@endif": "$loop->last", | ||
"@else": "@hasSection condition", | ||
"@hasSection": "@hasSection condition", | ||
"@unless": "@unless block", | ||
"@endunless": "@unless block", | ||
"@for": "@for block", | ||
"@endfor": "@for block", | ||
"@foreach": "@foreach block", | ||
"@endforeach": "@foreach block", | ||
"@forelse": "@forelse block", | ||
"@empty": "empty", | ||
"@endforelse": "@forelse block", | ||
"@while": "@while block", | ||
"@endwhile": "@while block", | ||
"@each": "@each loop", | ||
"@verbatim": "displaying JavaScript variables in a large portion of your template", | ||
"@endverbatim": "displaying JavaScript variables in a large portion of your template", | ||
"@push": "@push stack", | ||
"@endpush": "@push stack", | ||
"@stack": "@stack", | ||
"@inject": "@inject Service", | ||
"@can": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@endcan": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@elsecan": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@canany": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@endcanany": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@elsecanany": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@cannot": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@endcannot": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@elsecannot": "display a portion of the page only if the user is authorized to perform a given action.", | ||
"@php": "@php block code in view", | ||
"@endphp": "@php block code in view", | ||
"@includeIf": "include a view that may or may not be present, you should use the @includeIf directive", | ||
"@component": "component", | ||
"@endcomponent": "component", | ||
"@slot": "slot", | ||
"@endslot": "slot", | ||
"@isset": "isset", | ||
"@endisset": "isset", | ||
"@endempty": "empty", | ||
"@error": "error", | ||
"@enderror": "error", | ||
"@includeWhen": "includeWhen", | ||
"@auth": "auth", | ||
"@endauth": "auth", | ||
"@guest": "guest", | ||
"@endguest": "guest", | ||
"@switch": "switch", | ||
"@case": "switch", | ||
"@break": "switch", | ||
"@default": "switch", | ||
"@endswitch": "switch", | ||
"@includeFirst": "includeFirst", | ||
"@csrf": "form csrf field", | ||
"@method": "form method field", | ||
"@dump": "dump", | ||
"@lang": "lang", | ||
"@includeUnless": "includeUnless", | ||
"@props": "Blade component data properties", | ||
"@env": "env", | ||
"@endenv": "env", | ||
"@production": "production", | ||
"@endproduction": "production", | ||
"@once": "define a portion of template that will only be evaluated once per rendering cycle", | ||
"@endonce": "define a portion of template that will only be evaluated once per rendering cycle", | ||
"@aware": "Accessing data from a parent component (Laravel 8.64)", | ||
"@js": "This directive is useful to properly escape JSON within HTML quotes", | ||
"@class": "conditionally compiles a CSS class string. (Laravel 8.51)", | ||
"@checked": "This directive will echo checked if the provided condition evaluates to true (Laravel 9.x)", | ||
"@selected": "The @selected directive may be used to indicate if a given select option should be \"selected\" (Laravel 9.x)", | ||
"@disabled": "The @disabled directive may be used to indicate if a given element should be \"disabled\" (Laravel 9.x)" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"@livewireStyles": "Livewire Styles directive", | ||
"@livewireScripts": "Livewire Scripts directive", | ||
"@livewire": "Livewire nesting components" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
|
||
const generate = (filename, outputPath) => { | ||
fs.readFile(filename, 'utf8', (err, data) => { | ||
if (err) { | ||
console.error(err); | ||
return; | ||
} | ||
|
||
jsonData = JSON.parse(data); | ||
|
||
const output = {}; | ||
for (const key of Object.keys(jsonData)) { | ||
let body = ''; | ||
if (typeof jsonData[key]['body'] === 'string' || jsonData[key]['body'] instanceof String) { | ||
body = jsonData[key]['body']; | ||
} else if (Array.isArray(jsonData[key]['body'])) { | ||
body = jsonData[key]['body'].join(''); | ||
} | ||
|
||
if (body) { | ||
matches = body.match(/@.[a-zA-Z_0-9]*/g); | ||
if (matches) { | ||
matches.forEach((v) => { | ||
if (v !== '@{') { | ||
output[v] = jsonData[key]['description']; | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
|
||
if (!fs.existsSync(outputPath)) { | ||
fs.mkdirSync(path.dirname(outputPath), { recursive: true }); | ||
} | ||
|
||
fs.writeFileSync(outputPath, JSON.stringify(output, null, 2)); | ||
}); | ||
}; | ||
|
||
generate( | ||
path.join(path.dirname(__dirname), 'data', 'snippets', 'snippets.json'), | ||
path.join(path.dirname(__dirname), 'data', 'completion', 'blade-directive.json') | ||
); | ||
generate( | ||
path.join(path.dirname(__dirname), 'data', 'snippets', 'livewire.json'), | ||
path.join(path.dirname(__dirname), 'data', 'completion', 'livewire-directive.json') | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { | ||
CancellationToken, | ||
CompletionContext, | ||
CompletionItem, | ||
CompletionItemKind, | ||
CompletionItemProvider, | ||
CompletionList, | ||
ExtensionContext, | ||
LinesTextDocument, | ||
Position, | ||
workspace, | ||
} from 'coc.nvim'; | ||
|
||
import path from 'path'; | ||
import fs from 'fs'; | ||
|
||
type CompletionJsonType = { | ||
[key: string]: string; | ||
}; | ||
|
||
export class BladeDirectiveCompletionProvider implements CompletionItemProvider { | ||
private _context: ExtensionContext; | ||
private directiveJsonPaths: string[]; | ||
|
||
constructor(context: ExtensionContext) { | ||
this._context = context; | ||
this.directiveJsonPaths = [ | ||
path.join(this._context.extensionPath, 'data', 'completion', 'blade-directive.json'), | ||
path.join(this._context.extensionPath, 'data', 'completion', 'livewire-directive.json'), | ||
]; | ||
} | ||
|
||
async getCompletionItems(completionDataPath: string) { | ||
const completionList: CompletionItem[] = []; | ||
if (fs.existsSync(completionDataPath)) { | ||
const completionJsonText = fs.readFileSync(completionDataPath, 'utf8'); | ||
const completionJson: CompletionJsonType = JSON.parse(completionJsonText); | ||
if (completionJson) { | ||
Object.keys(completionJson).map((key) => { | ||
const docDataPath = path.join( | ||
this._context.extensionPath, | ||
'data', | ||
'documantation', | ||
'blade', | ||
key.replace('@', '') + '.md' | ||
); | ||
|
||
let documentationText: string | undefined; | ||
try { | ||
documentationText = fs.readFileSync(docDataPath, 'utf8'); | ||
} catch (e) { | ||
// noop | ||
documentationText = undefined; | ||
} | ||
|
||
completionList.push({ | ||
label: key, | ||
kind: CompletionItemKind.Text, | ||
insertText: key.replace('@', ''), | ||
detail: completionJson[key], | ||
documentation: documentationText, | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
return completionList; | ||
} | ||
|
||
async provideCompletionItems( | ||
//document: TextDocument, | ||
document: LinesTextDocument, | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
position: Position, | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
token: CancellationToken, | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
context: CompletionContext | ||
): Promise<CompletionItem[] | CompletionList> { | ||
const doc = workspace.getDocument(document.uri); | ||
if (!doc) return []; | ||
const wordRange = doc.getWordRangeAtPosition(Position.create(position.line, position.character - 1), '@'); | ||
if (!wordRange) return []; | ||
const text = document.getText(wordRange) || ''; | ||
if (!text) return []; | ||
|
||
if (!text.startsWith('@')) return []; | ||
|
||
const completionItemList: CompletionItem[] = []; | ||
this.directiveJsonPaths.forEach((v) => { | ||
this.getCompletionItems(v).then((vv) => completionItemList.push(...vv)); | ||
}); | ||
return completionItemList; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters