From b1fa8a278b5324f5f1ebfcfc8260932b2390e098 Mon Sep 17 00:00:00 2001 From: Pizca de Saber <79965488+pizcadesaber@users.noreply.github.com> Date: Sat, 25 Jan 2025 16:52:08 +0100 Subject: [PATCH] Better view completion --- changelog.md | 58 ++++++++++++++++++++++++----------------------- dist/extension.js | 8 +++---- package.json | 4 ++-- readme.md | 46 ++++++++++++++++--------------------- 4 files changed, 55 insertions(+), 61 deletions(-) diff --git a/changelog.md b/changelog.md index abcac9b..9c07f58 100644 --- a/changelog.md +++ b/changelog.md @@ -1,46 +1,50 @@ -# Change Log +# Changelog -All notable changes to the "livewire-jump" extension will be documented in this file. +All notable changes to the **Livewire Jump** extension will be documented in this file. ## [Unreleased] - No changes yet. +## [2.0.3] - 2025-01-25 + +- Improved the trigger for view autocompletion. +- Fixed autocompletion insertion to prevent it from being added after a `.`. + ## [2.0.2] - 2025-01-24 -- PHP component files are now read to identify view aliases within `view()`. It also handles multiple related views for easier navigation. -- Views are skipped as components if an `index.blade.php` file does not exist in the subdirectories. Livewire components are detected from the `app/Livewire` directory (Volt support is not included). -- **Breaking Change:** The structure of `view.dirs` has been updated. The key format is now `blade-dir|php-dir` and the value format is `view-prefix|tag-prefix`. Review your configuration if you’ve modified this setting, as the `view-prefix` and `tag-prefix` values are swapped. -- The count of views, components (Blade and Livewire), and associated `view.dirs` PHP classes is now displayed when the view is refreshed. +- PHP component files are now scanned to identify view aliases within `view()`. Additionally, multiple related views are handled to facilitate navigation. +- Views are skipped as components if no `index.blade.php` file exists in subdirectories. Livewire components are detected from the `app/Livewire` directory (Volt is not supported). +- **Breaking Change:** The `view.dirs` structure has been updated. The key format is now `blade-dir|php-dir`, and the value format is `view-prefix|tag-prefix`. Review your configuration if you’ve modified this setting, as `view-prefix` and `tag-prefix` values are now swapped. +- A count of views, components (Blade and Livewire), and PHP classes associated with `view.dirs` is now displayed when views are updated. -> **Important:** To apply these changes, select `Refresh Views` from the context menu of a PHP or Blade file. This will update your views to the new system. +> **Important:** To apply these changes, select `Update Views` from the context menu of a PHP or Blade file. This will update your views to the new system. ## [2.0.1] - 2025-01-17 -- Improves the names of the settings. -- Updates the `Go to *` command visibility after refreshing the views. -- `Clear Views` command that clears cached views. (`Ctrl+Shift+P` and search this command). +- Improved naming for settings. +- Updated the visibility of `Go to *` commands after views are refreshed. +- Added a `Clear views` command to remove cached views (`Ctrl+Shift+P` and search for this command). ## [2.0.0] - 2025-01-15 -- Completely refactored the core of the extension. All providers are now connected to a unified, large-scale caching system. -- Added a new contextual menu option to read all Blade files and register them locally in the workspace, allowing for faster loading instead of reading files in real-time. -- The current system is a significant improvement, especially with the new route selection configuration, where prefixes for views and tags can be specified. The key should be `bladeDir|classDir`, and the value `tagPrefix|aliasPrefix`. - +- Fully refactored the extension core. All providers are now connected to a unified and large-scale caching system. +- Added a new context menu option to scan all Blade files and register them locally in the workspace, enabling faster loading instead of real-time file reading. +- The new system is a significant improvement, particularly with the route selection configuration, where prefixes for views and tags can be specified. The key must be `bladeDir|classDir`, and the value `tagPrefix|aliasPrefix`. ## [1.3.0] - 2025-01-14 -- Changed tag navigation from definitions to clickable links for `` and ``. -- Added autocomplete for `view('')`, suggesting existing Blade files. +- Changed tag navigation from definitions to links for `` and ``. +- Added autocomplete for `view('')`, suggesting existing Blade files. - Minor bug fixes and improvements. ## [1.2.1] - 2025-01-10 - Added support for Blade component classes: - Navigate between `/resources/views/components/my-class.blade.php` and `/app/Views/Components/MyClass.php`. - - Commands dynamically adjust visibility based on the file type currently open (`Blade` or `PHP`). + - Commands dynamically adjust their visibility based on the open file type (`Blade` or `PHP`). - Improved command visibility logic: - - Commands like `Go to Blade View` or `Go to PHP Class` are now context-aware and will only appear in the context menu when applicable. + - Commands like `Go to Blade View` or `Go to PHP File` now only appear in the context menu when applicable. - Enhanced `Go to` functionality for Livewire components and Blade views. ## [1.2.0] - 2025-01-04 @@ -49,21 +53,19 @@ All notable changes to the "livewire-jump" extension will be documented in this - Right-click on a Livewire class file and select `Go to Livewire View`. - Added autocomplete for ` **Note:** Read the Features and Known Issues sections in the README.md for detailed instructions. This is a pre-release version. +> **Note:** Refer to the Features and Known Issues sections in the README.md for detailed instructions. This is a preliminary release. ## [1.1.0] - 2024-12-23 -- Improved Blade slot handling: - - Excluded `` elements from Livewire-related navigation and autocomplete suggestions. +- Improved handling of Blade slots: `` elements were excluded from navigation. - Minor performance improvements when navigating between Blade views and PHP classes. ## [1.0.0] - 2024-12-09 -- Initial release with foundational navigation features: - - Navigate from Livewire Blade views to their associated PHP classes using the context menu (`Right-click -> Go to Livewire Class`). - - Added `Ctrl+left_click` navigation support: - - From Blade views to Livewire component classes. - - From Blade component views to their associated PHP classes. +- Initial release with basic navigation features: + - Navigate from Livewire Blade views to their associated PHP classes using the context menu (`Right Click > Go to Livewire Class`). + - Navigate from PHP component classes to their associated Blade views (similarly, by selecting `Go to Blade View`). + - Added navigation support with `Ctrl+Left Click` on HTML component tags (`x-` and `livewire:`). \ No newline at end of file diff --git a/dist/extension.js b/dist/extension.js index d1bfe39..978a26b 100644 --- a/dist/extension.js +++ b/dist/extension.js @@ -1,7 +1,7 @@ -"use strict";var j=Object.defineProperty;var ie=Object.getOwnPropertyDescriptor;var oe=Object.getOwnPropertyNames;var re=Object.prototype.hasOwnProperty;var ae=(e,t)=>{for(var n in t)j(e,n,{get:t[n],enumerable:!0})},se=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of oe(t))!re.call(e,i)&&i!==n&&j(e,i,{get:()=>t[i],enumerable:!(o=ie(t,i))||o.enumerable});return e};var pe=e=>se(j({},"__esModule",{value:!0}),e);var fe={};ae(fe,{activate:()=>ce,deactivate:()=>ue});module.exports=pe(fe);var c=require("vscode");var l=require("vscode");var V=require("path"),w=require("vscode");var K=require("path"),x=require("vscode");function y(...e){if(!x.workspace.workspaceFolders)return;let t=x.workspace.workspaceFolders[0].uri;return e?x.Uri.file((0,K.join)(t.path,...e.filter(n=>!!n))):t}function H(e,t){let n=e.indexOf(t),o=n>0;return o&&(e.splice(n,1),e.unshift(t)),o}async function M(e){return new TextDecoder("utf-8").decode(await x.workspace.fs.readFile(e))}function W(e){e?x.workspace.openTextDocument(e).then(t=>{x.window.showTextDocument(t)},()=>{x.window.showInformationMessage("File not found: "+e?.fsPath)}):x.window.showInformationMessage("File Not found.")}function P(e,t){let n=x.workspace.getConfiguration("livewire-jump");return e?t?n.get(e,t):n.get(e):n}function X(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}var N=require("path"),C=require("vscode");var m,F,T=[];function _(e){T.length===1?W(T[0].uri):T.length>1&&C.window.showQuickPick(T,{placeHolder:"Choose an option"}).then(t=>{t?.uri&&(F==="php"?(m=m,H(m.aliases,t.label)&&Z(e)):F==="blade"&&(m=m,H(m.phpReferences,t.label)&&O(e)),W(t.uri))})}function U(){m=void 0,F=void 0,T=[],C.commands.executeCommand("setContext","livewire-jump.hasView",!1),C.commands.executeCommand("setContext","livewire-jump.hasClass",!1)}function k(e,t){if(!P("view.navigation",!0)||(U(),!t))return;let n=t.document.languageId,o=C.workspace.asRelativePath(t.document.uri.path,!1);n==="blade"?(m=E(e).find(i=>i.bladePath===o),m?.phpReferences&&m.phpReferences.length>0&&(F="blade",m.phpReferences.forEach(i=>{let r=y(i);r&&T.push({label:i,description:"PHP",uri:r})})),T.length>0&&C.commands.executeCommand("setContext","livewire-jump.hasClass",!0)):n==="php"&&(m=J(e).find(i=>i.path===o),F="php",m?.aliases.forEach(i=>{let r=E(e).find(a=>a.alias===i);if(r){let a=y(r.bladePath);a&&T.push({label:i,description:"View",uri:a})}}),T.length>0&&C.commands.executeCommand("setContext","livewire-jump.hasView",!0))}function le(e,t){let n=C.workspace.getWorkspaceFolder(t);if(!n)return;let o;if(e.bladePath)o=e.bladePath;else if(e.phpPath)o=e.phpPath;else return;return C.Uri.file((0,N.join)(n.uri.path,o))}function G(e,t,n){let o=S(e).find(i=>i.tag===t);return o?le(o,n):void 0}async function Q(e){if(!e)return[];let t=/\bview\s*\(\s*[\'"]([a-z0-9\.-]+)[\'"]/g,n=[],o=t.exec(e);for(;o;){let i=o[1];n.includes(i)||n.push(o[1]),o=t.exec(e)}return n}var I=[],h,f,g,D=[];function E(e){return h===void 0&&(h=e.workspaceState.get(R(e),[])),h}function O(e){e.workspaceState.update(R(e),h)}function Z(e){e.workspaceState.update(L(e),g)}function S(e){return f===void 0&&(f=e.workspaceState.get(z(e),[])),f}function J(e){return g===void 0&&(g=e.workspaceState.get(L(e),[])),g}async function q(e,t){let o=w.workspace.getConfiguration("livewire-jump").get("view.dirs",{});I=Object.entries(o).map(([r,a])=>de(r,a)),h=[],f=[],g=[];let i=w.workspace.getWorkspaceFolder(t.document.uri);if(i){D=[];for(let r of I)await te(r,"",i.uri);for(let r of I)await ee(r,"",i.uri),h!==void 0&&g.forEach(a=>{a.aliases=a.aliases.filter(s=>{let p=!1;return h?.forEach(d=>{d.alias===s&&(d.phpReferences.includes(a.path)||d.phpReferences.push(a.path),p=!0)}),p})});if(f===void 0)D=[];else for(;D.length>0;){let r=D.pop();r&&!f.some(a=>a.alias===r.alias)&&f.push(r)}}await e.workspaceState.update(R(e),h),await e.workspaceState.update(z(e),f),await e.workspaceState.update(L(e),g),w.window.showInformationMessage(`Refreshed Views: ${h.length} views, ${f.length} components, ${g.length} classes`),k(e,t)}async function Y(e){h=void 0,f=void 0,g=void 0,await e.workspaceState.update(R(e),h),await e.workspaceState.update(z(e),f),await e.workspaceState.update(L(e),g),U(),w.window.showInformationMessage("Cleared Views")}function de(e,t){let n=e.split(/\||:|\s/g),o=t.split(/\||\s/g),i=o[1],r;return i?.startsWith("x-")?r=1:i?.startsWith("livewire:")&&(r=2),{bladePath:n[0],phpPath:n[1],alias:o[0]??"",tag:i,componentType:r}}function R(e){return`${e.extension.id}.views`}function z(e){return`${e.extension.id}.components`}function L(e){return`${e.extension.id}.phpFiles`}async function ee(e,t,n){if(g===void 0&&f===void 0||!e.phpPath)return;let o=[];try{o=await w.workspace.fs.readDirectory(n.with({path:(0,V.join)(n.path,e.phpPath,t)}))}catch{return}for(let[i,r]of o){let a=(0,V.join)(t,i),s=(0,V.join)(e.phpPath,a);if(r===w.FileType.Directory&&!I.some(p=>s===p.phpPath))await ee(e,a,n);else if(r===w.FileType.File&&i.endsWith(".php")){let p=y(s),d=X(a.replace(/\//g,".").replace(/\.php$/,"")),u=p?await Q(await M(p)):[];if(u.length===0&&u.push(e.alias+d),g!==void 0){let v={aliases:u,path:s};g.push(v)}if(f!==void 0&&e.componentType&&e.tag){let v={phpPath:s,tag:e.tag+d,alias:u[0],type:e.componentType};f.push(v)}}}}async function te(e,t,n,o=!0){if(h===void 0||!e.bladePath)return;let i=[];try{i=await w.workspace.fs.readDirectory(n.with({path:(0,V.join)(n.path,e.bladePath,t)}))}catch{return}let r=e.componentType===1&&i.some(([a])=>a==="index.blade.php");r&&(i=i.filter(([a])=>a!=="index.blade.php"));for(let[a,s]of i){let p=(0,V.join)(t,a),d=(0,V.join)(e.bladePath,p);if(s===w.FileType.Directory&&!I.some(u=>d===u.bladePath))te(e,p,n,r);else if(s===w.FileType.File&&a.endsWith(".blade.php")){let u=p.replace(/\//g,".").replace(/\.blade\.php$/,""),v=e.alias+u,B={bladePath:d,alias:v,phpReferences:[]};if(h.push(B),e.componentType&&f!==void 0&&o&&e.componentType===1&&e.tag){let ne={bladePath:d,tag:e.tag+u,alias:v,type:e.componentType};D.push(ne)}}}}var A=class e{static TAG_REGEX=/<\/?((?:livewire:|x-)[a-z0-9][a-z0-9-\.]*)[\s\/$>]/g;context;constructor(t){this.context=t}provideCompletionItems(t,n){return P("blade.tag.completion",!0)?t.lineAt(n).text.slice(0,n.character).match(/<([a-z0-9-\.\:]*)$/i)?S(this.context).filter(r=>!!r.tag).map(r=>{let a=r.tag??"unknown",s=new l.CompletionItem(a,l.CompletionItemKind.Snippet);return a&&(s.detail="Component",s.insertText=new l.SnippetString(`${a} $0`),s.documentation=new l.MarkdownString(`Inserts a component: +"use strict";var H=Object.defineProperty;var re=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames;var se=Object.prototype.hasOwnProperty;var le=(e,t)=>{for(var n in t)H(e,n,{get:t[n],enumerable:!0})},pe=(e,t,n,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of ae(t))!se.call(e,i)&&i!==n&&H(e,i,{get:()=>t[i],enumerable:!(o=re(t,i))||o.enumerable});return e};var de=e=>pe(H({},"__esModule",{value:!0}),e);var ge={};le(ge,{activate:()=>ue,deactivate:()=>me});module.exports=de(ge);var u=require("vscode");var l=require("vscode");var V=require("path"),w=require("vscode");var _=require("path"),C=require("vscode");function y(...e){if(!C.workspace.workspaceFolders)return;let t=C.workspace.workspaceFolders[0].uri;return e?C.Uri.file((0,_.join)(t.path,...e.filter(n=>!!n))):t}function z(e,t){let n=e.indexOf(t),o=n>0;return o&&(e.splice(n,1),e.unshift(t)),o}async function Z(e){return new TextDecoder("utf-8").decode(await C.workspace.fs.readFile(e))}function W(e){e?C.workspace.openTextDocument(e).then(t=>{C.window.showTextDocument(t)},()=>{C.window.showInformationMessage("File not found: "+e?.fsPath)}):C.window.showInformationMessage("File Not found.")}function P(e,t){let n=C.workspace.getConfiguration("livewire-jump");return e?t?n.get(e,t):n.get(e):n}function q(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}var N=require("path"),v=require("vscode");var g,U,b=[];function K(e){b.length===1?W(b[0].uri):b.length>1&&v.window.showQuickPick(b,{placeHolder:"Choose an option"}).then(t=>{t?.uri&&(U==="php"?(g=g,z(g.aliases,t.label)&&X(e)):U==="blade"&&(g=g,z(g.phpReferences,t.label)&&O(e)),W(t.uri))})}function D(){g=void 0,U=void 0,b=[],v.commands.executeCommand("setContext","livewire-jump.hasView",!1),v.commands.executeCommand("setContext","livewire-jump.hasClass",!1)}function F(e,t){if(!P("view.navigation",!0)||(D(),!t))return;let n=t.document.languageId,o=v.workspace.asRelativePath(t.document.uri.path,!1);n==="blade"?(g=k(e).find(i=>i.bladePath===o),g?.phpReferences&&g.phpReferences.length>0&&(U="blade",g.phpReferences.forEach(i=>{let a=y(i);a&&b.push({label:i,description:"PHP",uri:a})})),b.length>0&&v.commands.executeCommand("setContext","livewire-jump.hasClass",!0)):n==="php"&&(g=J(e).find(i=>i.path===o),U="php",g?.aliases.forEach(i=>{let a=k(e).find(r=>r.alias===i);if(a){let r=y(a.bladePath);r&&b.push({label:i,description:"View",uri:r})}}),b.length>0&&v.commands.executeCommand("setContext","livewire-jump.hasView",!0))}function ce(e,t){let n=v.workspace.getWorkspaceFolder(t);if(!n)return;let o;if(e.bladePath)o=e.bladePath;else if(e.phpPath)o=e.phpPath;else return;return v.Uri.file((0,N.join)(n.uri.path,o))}function M(e,t,n){let o=I(e).find(i=>i.tag===t);return o?ce(o,n):void 0}async function Q(e){if(!e)return[];let t=/\bview\s*\(\s*[\'"]([a-z0-9\.-]+)[\'"]/g,n=[],o=t.exec(e);for(;o;){let i=o[1];n.includes(i)||n.push(o[1]),o=t.exec(e)}return n}var S=[],h,m,x,R=[];function k(e){return h===void 0&&(h=e.workspaceState.get(A(e),[])),h}function O(e){e.workspaceState.update(A(e),h)}function X(e){e.workspaceState.update(L(e),x)}function I(e){return m===void 0&&(m=e.workspaceState.get(G(e),[])),m}function J(e){return x===void 0&&(x=e.workspaceState.get(L(e),[])),x}async function Y(e,t){let o=w.workspace.getConfiguration("livewire-jump").get("view.dirs",{});S=Object.entries(o).map(([a,r])=>fe(a,r)),h=[],m=[],x=[];let i=w.workspace.getWorkspaceFolder(t.document.uri);if(i){R=[];for(let a of S)await ne(a,"",i.uri);for(let a of S)await te(a,"",i.uri),h!==void 0&&x.forEach(r=>{r.aliases=r.aliases.filter(s=>{let d=!1;return h?.forEach(c=>{c.alias===s&&(c.phpReferences.includes(r.path)||c.phpReferences.push(r.path),d=!0)}),d})});if(m===void 0)R=[];else for(;R.length>0;){let a=R.pop();a&&!m.some(r=>r.alias===a.alias)&&m.push(a)}}await e.workspaceState.update(A(e),h),await e.workspaceState.update(G(e),m),await e.workspaceState.update(L(e),x),w.window.showInformationMessage(`Refreshed Views: ${h.length} views, ${m.length} components, ${x.length} classes`),F(e,t)}async function ee(e){h=void 0,m=void 0,x=void 0,await e.workspaceState.update(A(e),h),await e.workspaceState.update(G(e),m),await e.workspaceState.update(L(e),x),D(),w.window.showInformationMessage("Cleared Views")}function fe(e,t){let n=e.split(/\||:|\s/g),o=t.split(/\||\s/g),i=o[1],a;return i?.startsWith("x-")?a=1:i?.startsWith("livewire:")&&(a=2),{bladePath:n[0],phpPath:n[1],alias:o[0]??"",tag:i,componentType:a}}function A(e){return`${e.extension.id}.views`}function G(e){return`${e.extension.id}.components`}function L(e){return`${e.extension.id}.phpFiles`}async function te(e,t,n){if(x===void 0&&m===void 0||!e.phpPath)return;let o=[];try{o=await w.workspace.fs.readDirectory(n.with({path:(0,V.join)(n.path,e.phpPath,t)}))}catch{return}for(let[i,a]of o){let r=(0,V.join)(t,i),s=(0,V.join)(e.phpPath,r);if(a===w.FileType.Directory&&!S.some(d=>s===d.phpPath))await te(e,r,n);else if(a===w.FileType.File&&i.endsWith(".php")){let d=y(s),c=q(r.replace(/\//g,".").replace(/\.php$/,"")),p=d?await Q(await Z(d)):[];if(p.length===0&&p.push(e.alias+c),x!==void 0){let f={aliases:p,path:s};x.push(f)}if(m!==void 0&&e.componentType&&e.tag){let f={phpPath:s,tag:e.tag+c,alias:p[0],type:e.componentType};m.push(f)}}}}async function ne(e,t,n,o=!0){if(h===void 0||!e.bladePath)return;let i=[];try{i=await w.workspace.fs.readDirectory(n.with({path:(0,V.join)(n.path,e.bladePath,t)}))}catch{return}let a=e.componentType===1&&i.some(([r])=>r==="index.blade.php");a&&(i=i.filter(([r])=>r!=="index.blade.php"));for(let[r,s]of i){let d=(0,V.join)(t,r),c=(0,V.join)(e.bladePath,d);if(s===w.FileType.Directory&&!S.some(p=>c===p.bladePath))ne(e,d,n,a);else if(s===w.FileType.File&&r.endsWith(".blade.php")){let p=d.replace(/\//g,".").replace(/\.blade\.php$/,""),f=e.alias+p,E={bladePath:c,alias:f,phpReferences:[]};if(h.push(E),e.componentType&&m!==void 0&&o&&e.componentType===1&&e.tag){let B={bladePath:c,tag:e.tag+p,alias:f,type:e.componentType};R.push(B)}}}}var $=class e{static TAG_REGEX=/<\/?((?:livewire:|x-)[a-z0-9][a-z0-9-\.]*)[\s\/$>]/g;context;constructor(t){this.context=t}provideCompletionItems(t,n){if(!P("blade.tag.completion",!0))return[];let i=t.lineAt(n).text.slice(0,n.character).match(/<([a-z0-9-\.\:]*)$/i);return i?I(this.context).filter(a=>!!a.tag).map(a=>{let r=a.tag??"unknown",s=new l.CompletionItem(r,l.CompletionItemKind.Snippet);return r&&(s.detail="Component",s.insertText=new l.SnippetString(`${r} $0`),s.documentation=new l.MarkdownString(`Inserts a component: \`\`\`html -<${a} /> -\`\`\``)),s}):[]:[]}provideDocumentLinks(t){if(!P("blade.tag.link",!0))return[];let n=[];for(let o=0;o=a&&n.character<=s){let p=new l.Range(new l.Position(n.line,a),new l.Position(n.line,s)),d=G(this.context,r,t.uri);if(!d)continue;if(d){let u=l.workspace.asRelativePath(d.fsPath);return new l.Hover(`Livewire Component: **${r}** +<${r} /> +\`\`\``),i.index&&(s.range=new l.Range(new l.Position(n.line,i.index),new l.Position(n.line,n.character)))),s}):[]}provideDocumentLinks(t,n){if(!P("blade.tag.link",!0))return[];let o=[];for(let i=0;i=s&&n.character<=d){let c=new l.Range(new l.Position(n.line,s),new l.Position(n.line,d)),p=M(this.context,r,t.uri);if(!p)continue;if(p){let f=l.workspace.asRelativePath(p.fsPath);return new l.Hover(`Livewire Component: **${r}** -Path: ${u}`,p)}}}return null}};var b=require("vscode");var $=class e{static VIEW_REGEX=/(?:view|layout|#\[Layout)\(['"]([^'"]*)['"]/g;context;loadedViews=[];constructor(t){this.context=t}provideCompletionItems(t,n,o,i){return P("view.completion",!0)?t.lineAt(n).text.substring(0,n.character).match(/\b(?:view|layout|#\[Layout|links)\(['"][^'"]*$/)?E(this.context).filter(s=>!!s.bladePath).map(s=>{let p=new b.CompletionItem(s.alias,b.CompletionItemKind.File);return p.detail="Laravel View",p.documentation=`View file: ${s.alias}`,p}):[]:[]}provideDocumentLinks(t,n){if(this.loadedViews=[],!P("view.link",!0))return[];let o=[],i=t.getText(),r;for(;(r=e.VIEW_REGEX.exec(i))!==null;){let a=r[1],s=this.findView(a),p=s?y(s.bladePath):void 0;if(p){let d=r.index+r[0].indexOf(a),u=d+a.length,v=t.positionAt(d),B=t.positionAt(u);o.push(new b.DocumentLink(new b.Range(v,B),p))}}return o}provideHover(t,n,o){P("view.hover",!0)}findView(t){let n=this.loadedViews.find(o=>o.alias===t);if(!n){let o=E(this.context).filter(i=>!!i.bladePath).find(i=>i.alias===t);return o&&this.loadedViews.push(o),o}return n}};function ce(e){let t={scheme:"file",language:"blade"},n={scheme:"file",language:"php"},o=new A(e),i=new $(e);e.subscriptions.push(c.languages.registerCompletionItemProvider(t,o,"<"),c.languages.registerDocumentLinkProvider(t,o),c.languages.registerHoverProvider(t,o),c.languages.registerCompletionItemProvider(t,i,"('"),c.languages.registerCompletionItemProvider(n,i,"('"),c.languages.registerDocumentLinkProvider(t,i),c.languages.registerDocumentLinkProvider(n,i),c.commands.registerTextEditorCommand("livewire-jump.refreshViews",r=>{q(e,r)}),c.commands.registerCommand("livewire-jump.goToClass",()=>{_(e)}),c.commands.registerCommand("livewire-jump.goToView",()=>{_(e)}),c.commands.registerCommand("livewire-jump.clearViews",async()=>{await Y(e)}),c.window.onDidChangeActiveTextEditor(r=>{k(e,r)}),c.workspace.onDidChangeConfiguration(r=>{r.affectsConfiguration("livewire-jump.view.navigation")&&(P("view.navigation",!0)?k(e,void 0):U())})),k(e,c.window.activeTextEditor),console.log("Livewire Jump up")}function ue(){}0&&(module.exports={activate,deactivate}); +Path: ${f}`,c)}}}return null}};var T=require("vscode");var j=class e{context;loadedViews=[];static regex="(?:"+["#\\[Layout","(?:^|[^A-Za-z0-9_:])(?:"+["view","links","layout"].join("|")+")"].join("|")+`)\\(['"]([a-zA-Z0-9\\.-]*)`;constructor(t){this.context=t}provideCompletionItems(t,n,o,i){if(P("view.completion",!0)===!1)return[];let a=t.lineAt(n).text,r=RegExp(e.regex+"$").exec(a.slice(0,n.character));if(!r)return[];let s=new T.Position(n.line,r.index+r[0].length-r[1].length),d=new T.Position(n.line,r.index+r[0].length),c=new T.Range(s,d);return(k(this.context)||[]).filter(p=>!!p.bladePath).map(p=>{let f=new T.CompletionItem(`${p.alias}`,T.CompletionItemKind.File);return f.detail="Blade View",f.documentation=`View: ${p.alias}`,f.range=c,f})}provideDocumentLinks(t,n){if(this.loadedViews=[],!P("view.link",!0))return[];let o=[],i=t.getText(),a=100,r=0,s,d=RegExp(e.regex+`['"]`,"g");for(;(s=d.exec(i))!==null&&ro.alias===t);if(!n){let o=k(this.context).filter(i=>!!i.bladePath).find(i=>i.alias===t);return o&&this.loadedViews.push(o),o}return n}};function ue(e){let t={scheme:"file",language:"blade"},n={scheme:"file",language:"php"},o=new $(e),i=new j(e);e.subscriptions.push(u.languages.registerCompletionItemProvider(t,o,"<"),u.languages.registerDocumentLinkProvider(t,o),u.languages.registerHoverProvider(t,o),u.languages.registerCompletionItemProvider([t,n],i,"'",'"'),u.languages.registerDocumentLinkProvider([t,n],i),u.commands.registerTextEditorCommand("livewire-jump.refreshViews",a=>{Y(e,a)}),u.commands.registerCommand("livewire-jump.goToClass",()=>{K(e)}),u.commands.registerCommand("livewire-jump.goToView",()=>{K(e)}),u.commands.registerCommand("livewire-jump.clearViews",async()=>{await ee(e)}),u.window.onDidChangeActiveTextEditor(a=>{F(e,a)}),u.workspace.onDidChangeConfiguration(a=>{a.affectsConfiguration("livewire-jump.view.navigation")&&(P("view.navigation",!0)?F(e,void 0):D())})),F(e,u.window.activeTextEditor),console.log("Livewire Jump up")}function me(){}0&&(module.exports={activate,deactivate}); diff --git a/package.json b/package.json index 32360da..70da8ed 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "Livewire Jump", "description": "A VS Code extension for navigating Laravel/Livewire project files.", "icon": "images/icon.jpg", - "version": "2.0.2", + "version": "2.0.3", "publisher": "pizca", "homepage": "https://github.com/pizcadesaber/vscode-livewire-jump", "repository": { @@ -100,7 +100,7 @@ }, { "command": "livewire-jump.goToClass", - "title": "Go to PHP Class" + "title": "Go to PHP File" }, { "command": "livewire-jump.goToView", diff --git a/readme.md b/readme.md index 7713142..ef5cd1f 100644 --- a/readme.md +++ b/readme.md @@ -1,55 +1,47 @@ # Livewire Jump Extension for VS Code -*Jump ahead, jump fast—speedy development!* +*Jump ahead and develop with speed!* -This extension allows you to quickly navigate between Livewire views, their associated PHP classes, and Blade components in Laravel projects. It streamlines the development workflow by providing an efficient way to jump from one file to another with just one click. +This extension allows you to quickly navigate between views and their associated PHP files in Laravel-Livewire projects. It optimizes your workflow by providing an efficient way to jump from one file to another with just a click. ## Features -- **Register components and autocomplete Blade and Livewire tags:** To enhance performance, a manual action has been added to register all components and use them for code autocompletion across different parts of your project. The `Refresh Views` action is only available in Blade and PHP language files. +- **Register components and autocomplete your code:** To improve performance, a manual action has been added to register all components and use them for code autocomplete in different parts of your project. This action is hidden outside the context of Blade and PHP documents. It also displays the number of views, components (Blade and Livewire), and PHP classes in `view.dirs` when views are updated. - ![Refresh views](https://github.com/pizcadesaber/vscode-livewire-jump/raw/HEAD/docs/images/refresh-views.gif) + ![Refresh Views](https://github.com/pizcadesaber/vscode-livewire-jump/raw/HEAD/docs/images/refresh-views.gif) - > **Note:** Updates based on file change observation are still pending implementation. + > **Note:** File-watching-based updates are not yet implemented. -- **Customize view discovery:** The `livewire-jump.view.dirs` setting allows you to customize the search by specifying prefixes for views and tags. Each key-value pair must follow this format: `"bladeDir|phpDir": "viewPrefix|tagPrefix"`. Keys also support `:` as a separator, but values do not, as it would conflict with `livewire:`. It’s not mandatory to specify both directories, but if you want to define only `phpDir`, you must prepend it with `|` so it is passed as the second argument. - - ![View discovery](https://github.com/pizcadesaber/vscode-livewire-jump/raw/HEAD/docs/images/view-discovery.jpg) - -- **Jump from Blade view to PHP class (and vice versa):** Easily navigate between Blade files and their corresponding PHP classes. Right-click on a Blade or PHP file and select `Go to PHP Class` or `Go to Blade Class`. +- **Jump between Blade views and PHP files:** Easily navigate between Blade files and their corresponding PHP classes. Right-click on a Blade or PHP file and select `Go to PHP File` or `Go to Blade File`. ![Go to PHP Class and View](https://github.com/pizcadesaber/vscode-livewire-jump/raw/HEAD/docs/images/view-class.gif) -- **Autocomplete component names:** The extension reads the paths found in `app/Livewire` and provides autocompletion for ` **Note:** The current behavior allows discovering Livewire components from their PHP classes (traditional). Additionally, Blade components are added with only view files in subdirectories if they contain an `index.blade.php` file. Tags are not added if `tagPrefix` is empty. ## Requirements -This extension has no additional dependencies. You only need a Laravel project with Livewire to take full advantage of its features. - -## Extension Setup +This extension is designed to support Laravel projects with additional Livewire support. -The extension doesn't require additional configuration. Simply install it, and it will be ready to use. However, ensure your project follows the standard Laravel and Livewire conventions for seamless integration. +It does not register any programming language. To ensure proper functionality, make sure you have PHP and Blade language support enabled, and that your `*.php` and `*.blade.php` files are associated with them. -If your project uses a custom folder structure, update the extension settings to match your paths. +## Extension Settings -## Important Note +It follows the latest Laravel and Livewire conventions to provide code autocomplete and link files for quick navigation. -To apply the latest changes, select **`Refresh Views`** from the context menu of a **PHP** or **Blade** file. This updates your views to the new system. +A set of editor settings can be found under `Settings > Extensions > Livewire Jump` to customize its behavior. However, ensure your project adheres to Laravel and Livewire’s standard conventions for seamless integration. ## Known Issues -If you encounter any bugs or unexpected behavior, feel free to report them in the repository. \ No newline at end of file +If you encounter errors or unexpected behavior, feel free to report them in the repository. \ No newline at end of file