jupyterlab_vscode_icons_extension 1.1.14 → 1.1.22

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 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="#616161" 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="#66bb6a" 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyterlab_vscode_icons_extension",
3
- "version": "1.1.14",
3
+ "version": "1.1.22",
4
4
  "description": "Jupyterlab extension with a shameless rip-off of the vscode-icons into our beloved environment",
5
5
  "keywords": [
6
6
  "jupyter",
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="#616161" 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="#66bb6a" 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