jupyterlab_vscode_icons_extension 1.1.14 → 1.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +60 -3
- package/package.json +1 -1
- package/src/index.ts +76 -3
package/lib/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
|
1
2
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
2
3
|
import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
|
|
3
4
|
import { LabIcon } from '@jupyterlab/ui-components';
|
|
@@ -128,7 +129,7 @@ const fileTypeConfigs = [
|
|
|
128
129
|
iconName: 'file-type-perl',
|
|
129
130
|
group: 'enableLanguageIcons'
|
|
130
131
|
},
|
|
131
|
-
// Shell scripts (.sh, .bash, .zsh) and batch files (.bat, .cmd) use custom icons with black backgrounds
|
|
132
|
+
// Shell scripts (.sh, .bash, .zsh, .fish, .csh, .nu) and batch files (.bat, .cmd) use custom icons with black backgrounds
|
|
132
133
|
// Registered separately below with custom SVGs
|
|
133
134
|
{
|
|
134
135
|
extensions: ['.ps1'],
|
|
@@ -445,6 +446,9 @@ const plugin = {
|
|
|
445
446
|
const pythonPackageDataUri = `data:image/svg+xml;base64,${btoa(pythonPackageSvg)}`;
|
|
446
447
|
const venvSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><g transform="scale(-1,1) translate(-32,0)"><path d="M27.4,5.5H18.1L16,9.7H4.3V26.5H29.5V5.5Zm0,4.2H19.2l1.1-2.1h7.1Z" fill="#9575cd"/><g transform="translate(22,22) scale(1.25)" fill="#bababa"><path d="M-1.2,-6 L1.2,-6 L1.5,-4.5 L2.8,-4 L4,-5 L5.5,-3.5 L4.5,-2.3 L5,-1 L6.5,-0.8 L6.5,1.2 L5,1.5 L4.5,2.8 L5.5,4 L4,5.5 L2.8,4.5 L1.5,5 L1.2,6.5 L-1.2,6.5 L-1.5,5 L-2.8,4.5 L-4,5.5 L-5.5,4 L-4.5,2.8 L-5,1.5 L-6.5,1.2 L-6.5,-0.8 L-5,-1 L-4.5,-2.3 L-5.5,-3.5 L-4,-5 L-2.8,-4 L-1.5,-4.5 Z"/><circle cx="0" cy="0" r="2.5" fill="#9575cd"/></g></g></svg>';
|
|
447
448
|
const venvDataUri = `data:image/svg+xml;base64,${btoa(venvSvg)}`;
|
|
449
|
+
// Executable file icon - JupyterLab standard file icon with play triangle overlay
|
|
450
|
+
const executableSvg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22"><path fill="#909090" d="m19.3 8.2-5.5-5.5c-.3-.3-.7-.5-1.2-.5H3.9c-.8.1-1.6.9-1.6 1.8v14.1c0 .9.7 1.6 1.6 1.6h14.2c.9 0 1.6-.7 1.6-1.6V9.4c.1-.5-.1-.9-.4-1.2m-5.8-3.3 3.4 3.6h-3.4zm3.9 12.7H4.7c-.1 0-.2 0-.2-.2V4.7c0-.2.1-.3.2-.3h7.2v4.4s0 .8.3 1.1 1.1.3 1.1.3h4.3v7.2s-.1.2-.2.2"/><path fill="#00e676" stroke="#1b5e20" stroke-width="0.8" d="M12,12 L20,16 L12,20 Z"/></svg>';
|
|
451
|
+
const executableDataUri = `data:image/svg+xml;base64,${btoa(executableSvg)}`;
|
|
448
452
|
// Inject CSS that overrides icons for .py and .md files
|
|
449
453
|
// Note: Jupytext marks .py and .md files as type="notebook", so we need to
|
|
450
454
|
// use JavaScript to detect and mark these files for CSS targeting
|
|
@@ -664,6 +668,22 @@ const plugin = {
|
|
|
664
668
|
background-repeat: no-repeat;
|
|
665
669
|
background-position: center;
|
|
666
670
|
}
|
|
671
|
+
|
|
672
|
+
/* Override executable file icons */
|
|
673
|
+
.jp-DirListing-item[data-executable] .jp-DirListing-itemIcon svg,
|
|
674
|
+
.jp-DirListing-item[data-executable] .jp-DirListing-itemIcon img {
|
|
675
|
+
display: none !important;
|
|
676
|
+
}
|
|
677
|
+
.jp-DirListing-item[data-executable] .jp-DirListing-itemIcon::before {
|
|
678
|
+
content: '';
|
|
679
|
+
display: inline-block;
|
|
680
|
+
width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
|
|
681
|
+
height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
|
|
682
|
+
background-image: url('${executableDataUri}');
|
|
683
|
+
background-size: contain;
|
|
684
|
+
background-repeat: no-repeat;
|
|
685
|
+
background-position: center;
|
|
686
|
+
}
|
|
667
687
|
`;
|
|
668
688
|
// Add CSS to make JavaScript and .env icons less bright
|
|
669
689
|
style.textContent += `
|
|
@@ -729,16 +749,47 @@ const plugin = {
|
|
|
729
749
|
pythonPackagesCache = { path: currentPath, packages };
|
|
730
750
|
return packages;
|
|
731
751
|
};
|
|
752
|
+
// Cache for executable file detection (per directory)
|
|
753
|
+
let executablesCache = null;
|
|
754
|
+
// Detect executable files via server API
|
|
755
|
+
const detectExecutables = async () => {
|
|
756
|
+
if (!settings.enableExecutableIcons) {
|
|
757
|
+
return new Set();
|
|
758
|
+
}
|
|
759
|
+
const currentPath = (defaultFileBrowser === null || defaultFileBrowser === void 0 ? void 0 : defaultFileBrowser.model.path) || '';
|
|
760
|
+
// Return cached result if same directory
|
|
761
|
+
if ((executablesCache === null || executablesCache === void 0 ? void 0 : executablesCache.path) === currentPath) {
|
|
762
|
+
return executablesCache.executables;
|
|
763
|
+
}
|
|
764
|
+
const executables = new Set();
|
|
765
|
+
try {
|
|
766
|
+
const baseUrl = PageConfig.getBaseUrl();
|
|
767
|
+
const apiUrl = URLExt.join(baseUrl, 'vscode-icons', 'executables');
|
|
768
|
+
const response = await fetch(`${apiUrl}?path=${encodeURIComponent(currentPath)}`);
|
|
769
|
+
if (response.ok) {
|
|
770
|
+
const files = await response.json();
|
|
771
|
+
files.forEach(f => executables.add(f));
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
catch (_a) {
|
|
775
|
+
// Ignore errors - no executables detected
|
|
776
|
+
}
|
|
777
|
+
executablesCache = { path: currentPath, executables };
|
|
778
|
+
return executables;
|
|
779
|
+
};
|
|
732
780
|
// Invalidate cache on directory change
|
|
733
781
|
if (defaultFileBrowser) {
|
|
734
782
|
defaultFileBrowser.model.pathChanged.connect(() => {
|
|
735
783
|
pythonPackagesCache = null;
|
|
784
|
+
executablesCache = null;
|
|
736
785
|
});
|
|
737
786
|
}
|
|
738
787
|
// Add a MutationObserver to mark special files in the file browser
|
|
739
788
|
const markSpecialFiles = async () => {
|
|
740
789
|
// Get Python packages for current directory (cached)
|
|
741
790
|
const pythonPackages = await detectPythonPackages();
|
|
791
|
+
// Get executable files for current directory (cached, only if setting enabled)
|
|
792
|
+
const executables = await detectExecutables();
|
|
742
793
|
// Process ALL items - clear wrong attributes and set correct ones
|
|
743
794
|
const allItems = document.querySelectorAll('.jp-DirListing-item');
|
|
744
795
|
allItems.forEach(item => {
|
|
@@ -817,6 +868,11 @@ const plugin = {
|
|
|
817
868
|
nameLower === 'conftest.py') {
|
|
818
869
|
item.setAttribute('data-pytest', 'true');
|
|
819
870
|
}
|
|
871
|
+
// Mark executable files if setting is enabled (uses server API for +x detection)
|
|
872
|
+
item.removeAttribute('data-executable');
|
|
873
|
+
if (settings.enableExecutableIcons && executables.has(name)) {
|
|
874
|
+
item.setAttribute('data-executable', 'true');
|
|
875
|
+
}
|
|
820
876
|
// Check if this is a directory (folder)
|
|
821
877
|
const isDir = fileType === 'directory' ||
|
|
822
878
|
item.classList.contains('jp-DirListing-directory');
|
|
@@ -884,7 +940,8 @@ const plugin = {
|
|
|
884
940
|
enableDataIcons: true,
|
|
885
941
|
enableConfigIcons: true,
|
|
886
942
|
enableDocIcons: true,
|
|
887
|
-
enableImageIcons: true
|
|
943
|
+
enableImageIcons: true,
|
|
944
|
+
enableExecutableIcons: false
|
|
888
945
|
};
|
|
889
946
|
// Function to register file types based on settings
|
|
890
947
|
const registerFileTypes = () => {
|
|
@@ -1037,7 +1094,7 @@ const plugin = {
|
|
|
1037
1094
|
docRegistry.addFileType({
|
|
1038
1095
|
name: 'vscode-shell',
|
|
1039
1096
|
displayName: 'Shell Script',
|
|
1040
|
-
extensions: ['.sh', '.bash', '.zsh'],
|
|
1097
|
+
extensions: ['.sh', '.bash', '.zsh', '.fish', '.csh', '.nu'],
|
|
1041
1098
|
fileFormat: 'text',
|
|
1042
1099
|
contentType: 'file',
|
|
1043
1100
|
icon: shellIcon
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
JupyterFrontEnd,
|
|
3
3
|
JupyterFrontEndPlugin
|
|
4
4
|
} from '@jupyterlab/application';
|
|
5
|
+
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
|
5
6
|
import { ISettingRegistry } from '@jupyterlab/settingregistry';
|
|
6
7
|
import { IDefaultFileBrowser } from '@jupyterlab/filebrowser';
|
|
7
8
|
import { LabIcon } from '@jupyterlab/ui-components';
|
|
@@ -18,6 +19,7 @@ interface IIconSettings {
|
|
|
18
19
|
enableConfigIcons: boolean;
|
|
19
20
|
enableDocIcons: boolean;
|
|
20
21
|
enableImageIcons: boolean;
|
|
22
|
+
enableExecutableIcons: boolean;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
/**
|
|
@@ -157,7 +159,7 @@ const fileTypeConfigs: IFileTypeConfig[] = [
|
|
|
157
159
|
iconName: 'file-type-perl',
|
|
158
160
|
group: 'enableLanguageIcons'
|
|
159
161
|
},
|
|
160
|
-
// Shell scripts (.sh, .bash, .zsh) and batch files (.bat, .cmd) use custom icons with black backgrounds
|
|
162
|
+
// Shell scripts (.sh, .bash, .zsh, .fish, .csh, .nu) and batch files (.bat, .cmd) use custom icons with black backgrounds
|
|
161
163
|
// Registered separately below with custom SVGs
|
|
162
164
|
{
|
|
163
165
|
extensions: ['.ps1'],
|
|
@@ -498,6 +500,10 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
498
500
|
const venvSvg =
|
|
499
501
|
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><g transform="scale(-1,1) translate(-32,0)"><path d="M27.4,5.5H18.1L16,9.7H4.3V26.5H29.5V5.5Zm0,4.2H19.2l1.1-2.1h7.1Z" fill="#9575cd"/><g transform="translate(22,22) scale(1.25)" fill="#bababa"><path d="M-1.2,-6 L1.2,-6 L1.5,-4.5 L2.8,-4 L4,-5 L5.5,-3.5 L4.5,-2.3 L5,-1 L6.5,-0.8 L6.5,1.2 L5,1.5 L4.5,2.8 L5.5,4 L4,5.5 L2.8,4.5 L1.5,5 L1.2,6.5 L-1.2,6.5 L-1.5,5 L-2.8,4.5 L-4,5.5 L-5.5,4 L-4.5,2.8 L-5,1.5 L-6.5,1.2 L-6.5,-0.8 L-5,-1 L-4.5,-2.3 L-5.5,-3.5 L-4,-5 L-2.8,-4 L-1.5,-4.5 Z"/><circle cx="0" cy="0" r="2.5" fill="#9575cd"/></g></g></svg>';
|
|
500
502
|
const venvDataUri = `data:image/svg+xml;base64,${btoa(venvSvg)}`;
|
|
503
|
+
// Executable file icon - JupyterLab standard file icon with play triangle overlay
|
|
504
|
+
const executableSvg =
|
|
505
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22"><path fill="#909090" d="m19.3 8.2-5.5-5.5c-.3-.3-.7-.5-1.2-.5H3.9c-.8.1-1.6.9-1.6 1.8v14.1c0 .9.7 1.6 1.6 1.6h14.2c.9 0 1.6-.7 1.6-1.6V9.4c.1-.5-.1-.9-.4-1.2m-5.8-3.3 3.4 3.6h-3.4zm3.9 12.7H4.7c-.1 0-.2 0-.2-.2V4.7c0-.2.1-.3.2-.3h7.2v4.4s0 .8.3 1.1 1.1.3 1.1.3h4.3v7.2s-.1.2-.2.2"/><path fill="#00e676" stroke="#1b5e20" stroke-width="0.8" d="M12,12 L20,16 L12,20 Z"/></svg>';
|
|
506
|
+
const executableDataUri = `data:image/svg+xml;base64,${btoa(executableSvg)}`;
|
|
501
507
|
|
|
502
508
|
// Inject CSS that overrides icons for .py and .md files
|
|
503
509
|
// Note: Jupytext marks .py and .md files as type="notebook", so we need to
|
|
@@ -718,6 +724,22 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
718
724
|
background-repeat: no-repeat;
|
|
719
725
|
background-position: center;
|
|
720
726
|
}
|
|
727
|
+
|
|
728
|
+
/* Override executable file icons */
|
|
729
|
+
.jp-DirListing-item[data-executable] .jp-DirListing-itemIcon svg,
|
|
730
|
+
.jp-DirListing-item[data-executable] .jp-DirListing-itemIcon img {
|
|
731
|
+
display: none !important;
|
|
732
|
+
}
|
|
733
|
+
.jp-DirListing-item[data-executable] .jp-DirListing-itemIcon::before {
|
|
734
|
+
content: '';
|
|
735
|
+
display: inline-block;
|
|
736
|
+
width: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
|
|
737
|
+
height: calc(var(--jp-ui-font-size1, 13px) * var(--jp-custom-icon-scale, 1.5));
|
|
738
|
+
background-image: url('${executableDataUri}');
|
|
739
|
+
background-size: contain;
|
|
740
|
+
background-repeat: no-repeat;
|
|
741
|
+
background-position: center;
|
|
742
|
+
}
|
|
721
743
|
`;
|
|
722
744
|
|
|
723
745
|
// Add CSS to make JavaScript and .env icons less bright
|
|
@@ -795,10 +817,52 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
795
817
|
return packages;
|
|
796
818
|
};
|
|
797
819
|
|
|
820
|
+
// Cache for executable file detection (per directory)
|
|
821
|
+
let executablesCache: { path: string; executables: Set<string> } | null =
|
|
822
|
+
null;
|
|
823
|
+
|
|
824
|
+
// Detect executable files via server API
|
|
825
|
+
const detectExecutables = async (): Promise<Set<string>> => {
|
|
826
|
+
if (!settings.enableExecutableIcons) {
|
|
827
|
+
return new Set<string>();
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
const currentPath = defaultFileBrowser?.model.path || '';
|
|
831
|
+
|
|
832
|
+
// Return cached result if same directory
|
|
833
|
+
if (executablesCache?.path === currentPath) {
|
|
834
|
+
return executablesCache.executables;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
const executables = new Set<string>();
|
|
838
|
+
|
|
839
|
+
try {
|
|
840
|
+
const baseUrl = PageConfig.getBaseUrl();
|
|
841
|
+
const apiUrl = URLExt.join(
|
|
842
|
+
baseUrl,
|
|
843
|
+
'vscode-icons',
|
|
844
|
+
'executables'
|
|
845
|
+
);
|
|
846
|
+
const response = await fetch(
|
|
847
|
+
`${apiUrl}?path=${encodeURIComponent(currentPath)}`
|
|
848
|
+
);
|
|
849
|
+
if (response.ok) {
|
|
850
|
+
const files: string[] = await response.json();
|
|
851
|
+
files.forEach(f => executables.add(f));
|
|
852
|
+
}
|
|
853
|
+
} catch {
|
|
854
|
+
// Ignore errors - no executables detected
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
executablesCache = { path: currentPath, executables };
|
|
858
|
+
return executables;
|
|
859
|
+
};
|
|
860
|
+
|
|
798
861
|
// Invalidate cache on directory change
|
|
799
862
|
if (defaultFileBrowser) {
|
|
800
863
|
defaultFileBrowser.model.pathChanged.connect(() => {
|
|
801
864
|
pythonPackagesCache = null;
|
|
865
|
+
executablesCache = null;
|
|
802
866
|
});
|
|
803
867
|
}
|
|
804
868
|
|
|
@@ -806,6 +870,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
806
870
|
const markSpecialFiles = async () => {
|
|
807
871
|
// Get Python packages for current directory (cached)
|
|
808
872
|
const pythonPackages = await detectPythonPackages();
|
|
873
|
+
// Get executable files for current directory (cached, only if setting enabled)
|
|
874
|
+
const executables = await detectExecutables();
|
|
809
875
|
|
|
810
876
|
// Process ALL items - clear wrong attributes and set correct ones
|
|
811
877
|
const allItems = document.querySelectorAll('.jp-DirListing-item');
|
|
@@ -899,6 +965,12 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
899
965
|
item.setAttribute('data-pytest', 'true');
|
|
900
966
|
}
|
|
901
967
|
|
|
968
|
+
// Mark executable files if setting is enabled (uses server API for +x detection)
|
|
969
|
+
item.removeAttribute('data-executable');
|
|
970
|
+
if (settings.enableExecutableIcons && executables.has(name)) {
|
|
971
|
+
item.setAttribute('data-executable', 'true');
|
|
972
|
+
}
|
|
973
|
+
|
|
902
974
|
// Check if this is a directory (folder)
|
|
903
975
|
const isDir =
|
|
904
976
|
fileType === 'directory' ||
|
|
@@ -973,7 +1045,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
973
1045
|
enableDataIcons: true,
|
|
974
1046
|
enableConfigIcons: true,
|
|
975
1047
|
enableDocIcons: true,
|
|
976
|
-
enableImageIcons: true
|
|
1048
|
+
enableImageIcons: true,
|
|
1049
|
+
enableExecutableIcons: false
|
|
977
1050
|
};
|
|
978
1051
|
|
|
979
1052
|
// Function to register file types based on settings
|
|
@@ -1152,7 +1225,7 @@ const plugin: JupyterFrontEndPlugin<void> = {
|
|
|
1152
1225
|
docRegistry.addFileType({
|
|
1153
1226
|
name: 'vscode-shell',
|
|
1154
1227
|
displayName: 'Shell Script',
|
|
1155
|
-
extensions: ['.sh', '.bash', '.zsh'],
|
|
1228
|
+
extensions: ['.sh', '.bash', '.zsh', '.fish', '.csh', '.nu'],
|
|
1156
1229
|
fileFormat: 'text',
|
|
1157
1230
|
contentType: 'file',
|
|
1158
1231
|
icon: shellIcon
|