3512c38a88f604c46c575e225edf95288331495ef14d2e64cf76dabe6adfe1b45cea9f6ad88c7da59db06f8d4ea406542a4a774fbb2c335f9422015a14534f 4.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import { Schemas } from '../../../base/common/network.js';
  6. import { DataUri } from '../../../base/common/resources.js';
  7. import { PLAINTEXT_LANGUAGE_ID } from '../languages/modesRegistry.js';
  8. import { FileKind } from '../../../platform/files/common/files.js';
  9. const fileIconDirectoryRegex = /(?:\/|^)(?:([^\/]+)\/)?([^\/]+)$/;
  10. export function getIconClasses(modelService, languageService, resource, fileKind) {
  11. // we always set these base classes even if we do not have a path
  12. const classes = fileKind === FileKind.ROOT_FOLDER ? ['rootfolder-icon'] : fileKind === FileKind.FOLDER ? ['folder-icon'] : ['file-icon'];
  13. if (resource) {
  14. // Get the path and name of the resource. For data-URIs, we need to parse specially
  15. let name;
  16. if (resource.scheme === Schemas.data) {
  17. const metadata = DataUri.parseMetaData(resource);
  18. name = metadata.get(DataUri.META_DATA_LABEL);
  19. }
  20. else {
  21. const match = resource.path.match(fileIconDirectoryRegex);
  22. if (match) {
  23. name = cssEscape(match[2].toLowerCase());
  24. if (match[1]) {
  25. classes.push(`${cssEscape(match[1].toLowerCase())}-name-dir-icon`); // parent directory
  26. }
  27. }
  28. else {
  29. name = cssEscape(resource.authority.toLowerCase());
  30. }
  31. }
  32. // Folders
  33. if (fileKind === FileKind.FOLDER) {
  34. classes.push(`${name}-name-folder-icon`);
  35. }
  36. // Files
  37. else {
  38. // Name & Extension(s)
  39. if (name) {
  40. classes.push(`${name}-name-file-icon`);
  41. classes.push(`name-file-icon`); // extra segment to increase file-name score
  42. // Avoid doing an explosive combination of extensions for very long filenames
  43. // (most file systems do not allow files > 255 length) with lots of `.` characters
  44. // https://github.com/microsoft/vscode/issues/116199
  45. if (name.length <= 255) {
  46. const dotSegments = name.split('.');
  47. for (let i = 1; i < dotSegments.length; i++) {
  48. classes.push(`${dotSegments.slice(i).join('.')}-ext-file-icon`); // add each combination of all found extensions if more than one
  49. }
  50. }
  51. classes.push(`ext-file-icon`); // extra segment to increase file-ext score
  52. }
  53. // Detected Mode
  54. const detectedLanguageId = detectLanguageId(modelService, languageService, resource);
  55. if (detectedLanguageId) {
  56. classes.push(`${cssEscape(detectedLanguageId)}-lang-file-icon`);
  57. }
  58. }
  59. }
  60. return classes;
  61. }
  62. function detectLanguageId(modelService, languageService, resource) {
  63. if (!resource) {
  64. return null; // we need a resource at least
  65. }
  66. let languageId = null;
  67. // Data URI: check for encoded metadata
  68. if (resource.scheme === Schemas.data) {
  69. const metadata = DataUri.parseMetaData(resource);
  70. const mime = metadata.get(DataUri.META_DATA_MIME);
  71. if (mime) {
  72. languageId = languageService.getLanguageIdByMimeType(mime);
  73. }
  74. }
  75. // Any other URI: check for model if existing
  76. else {
  77. const model = modelService.getModel(resource);
  78. if (model) {
  79. languageId = model.getLanguageId();
  80. }
  81. }
  82. // only take if the language id is specific (aka no just plain text)
  83. if (languageId && languageId !== PLAINTEXT_LANGUAGE_ID) {
  84. return languageId;
  85. }
  86. // otherwise fallback to path based detection
  87. return languageService.guessLanguageIdByFilepathOrFirstLine(resource);
  88. }
  89. export function cssEscape(str) {
  90. return str.replace(/[\11\12\14\15\40]/g, '/'); // HTML class names can not contain certain whitespace characters, use / instead, which doesn't exist in file names.
  91. }