diff --git a/.github/commands.yml b/.github/commands.yml index 0e78ac749fa..c649e6c4d89 100644 --- a/.github/commands.yml +++ b/.github/commands.yml @@ -96,7 +96,7 @@ { type: 'comment', name: 'confirmationPending', - allowUsers: ['cleidigh', 'usernamehw'], + allowUsers: ['cleidigh', 'usernamehw', 'gjsjohnmurray', 'IllusionMH'], action: 'updateLabels', addLabel: 'confirmation-pending', removeLabel: 'confirmed' @@ -116,6 +116,14 @@ addLabel: 'needs more info', comment: "Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!" }, + { + type: 'label', + name: '*needs more info', + action: 'updateLabels', + addLabel: 'needs more info', + removeLabel: '*needs more info', + comment: "Thanks for creating this issue! We figured it's missing some basic information or in some other way doesn't follow our [issue reporting](https://aka.ms/vscodeissuereporting) guidelines. Please take the time to review these and update the issue.\n\nHappy Coding!" + }, { type: 'comment', name: 'a11ymas', @@ -123,5 +131,12 @@ action: 'updateLabels', addLabel: 'a11ymas' }, + { + type: 'label', + name: '*needs more info', + action: 'updateLabels', + addLabel: 'needs more info', + removeLabel: '*needs more info' + }, ] } diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index 1723a82b437..3c85dd690d5 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -31,7 +31,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.34", + "version": "0.0.35", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index 6f37821c775..578fae31a19 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -54,7 +54,7 @@ function createCompile(src: string, build: boolean, emitError?: boolean) { const input = es.through(); const output = input .pipe(utf8Filter) - .pipe(bom()) + .pipe(bom()) // this is required to preserve BOM in test files that loose it otherwise .pipe(utf8Filter.restore) .pipe(tsFilter) .pipe(util.loadSourcemaps()) diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 2e2a20d89ad..581d2badaf0 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -50,6 +50,10 @@ "name": "vs/workbench/contrib/comments", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/testCustomEditors", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/debug", "project": "vscode-workbench" @@ -198,6 +202,10 @@ "name": "vs/workbench/services/actions", "project": "vscode-workbench" }, + { + "name": "vs/workbench/services/authToken", + "project": "vscode-workbench" + }, { "name": "vs/workbench/services/bulkEdit", "project": "vscode-workbench" diff --git a/build/win32/code.iss b/build/win32/code.iss index ee70efb974d..0e2ed70d64a 100644 --- a/build/win32/code.iss +++ b/build/win32/code.iss @@ -957,10 +957,10 @@ Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBas Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBasename}.exe\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resources\app\resources\win32\default.ico" Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\Applications\{#ExeBasename}.exe\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1""" -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open w&ith {#ShellNameShort}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu, {#ShellNameShort}}"; Tasks: addcontextmenufiles; Flags: uninsdeletekey Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufiles Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\*\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%1"""; Tasks: addcontextmenufiles -Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open w&ith {#ShellNameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey +Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "{cm:OpenWithCodeContextMenu, {#ShellNameShort}}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}"; ValueType: expandsz; ValueName: "Icon"; ValueData: "{app}\{#ExeBasename}.exe"; Tasks: addcontextmenufolders Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\shell\{#RegValueName}\command"; ValueType: expandsz; ValueName: ""; ValueData: """{app}\{#ExeBasename}.exe"" ""%V"""; Tasks: addcontextmenufolders Root: {#SoftwareClassesRootKey}; Subkey: "Software\Classes\directory\background\shell\{#RegValueName}"; ValueType: expandsz; ValueName: ""; ValueData: "Open w&ith {#ShellNameShort}"; Tasks: addcontextmenufolders; Flags: uninsdeletekey diff --git a/build/win32/i18n/messages.de.isl b/build/win32/i18n/messages.de.isl index 755652bcdbe..6a9f29aa9c2 100644 --- a/build/win32/i18n/messages.de.isl +++ b/build/win32/i18n/messages.de.isl @@ -5,4 +5,5 @@ AssociateWithFiles=%1 als Editor f AddToPath=Zu PATH hinzufgen (nach dem Neustart verfgbar) RunAfter=%1 nach der Installation ausfhren Other=Andere: -SourceFile=%1-Quelldatei \ No newline at end of file +SourceFile=%1-Quelldatei +OpenWithCodeContextMenu=Mit %1 ffnen \ No newline at end of file diff --git a/build/win32/i18n/messages.en.isl b/build/win32/i18n/messages.en.isl index a6aab59b95a..6535824eed6 100644 --- a/build/win32/i18n/messages.en.isl +++ b/build/win32/i18n/messages.en.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Register %1 as an editor for supported file types AddToPath=Add to PATH (requires shell restart) RunAfter=Run %1 after installation Other=Other: -SourceFile=%1 Source File \ No newline at end of file +SourceFile=%1 Source File +OpenWithCodeContextMenu=Open with %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.es.isl b/build/win32/i18n/messages.es.isl index e8d5af64b61..e51f099f9a1 100644 --- a/build/win32/i18n/messages.es.isl +++ b/build/win32/i18n/messages.es.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Registrar %1 como editor para tipos de archivo admitidos AddToPath=Agregar a PATH (disponible despus de reiniciar) RunAfter=Ejecutar %1 despus de la instalacin Other=Otros: -SourceFile=Archivo de origen %1 \ No newline at end of file +SourceFile=Archivo de origen %1 +OpenWithCodeContextMenu=Abrir con %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.fr.isl b/build/win32/i18n/messages.fr.isl index 3e17036f806..df140418625 100644 --- a/build/win32/i18n/messages.fr.isl +++ b/build/win32/i18n/messages.fr.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Inscrire %1 en tant qu' AddToPath=Ajouter PATH (disponible aprs le redmarrage) RunAfter=Excuter %1 aprs l'installation Other=Autre: -SourceFile=Fichier source %1 \ No newline at end of file +SourceFile=Fichier source %1 +OpenWithCodeContextMenu=Ouvrir avec %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.hu.isl b/build/win32/i18n/messages.hu.isl index f141ad1b24a..b64553da8e6 100644 --- a/build/win32/i18n/messages.hu.isl +++ b/build/win32/i18n/messages.hu.isl @@ -5,4 +5,5 @@ AssociateWithFiles=%1 regisztr AddToPath=Hozzads a PATH-hoz (jraindts utn lesz elrhet) RunAfter=%1 indtsa a telepts utn Other=Egyb: -SourceFile=%1 forrsfjl \ No newline at end of file +SourceFile=%1 forrsfjl +OpenWithCodeContextMenu=Megnyits a kvetkezvel: %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.it.isl b/build/win32/i18n/messages.it.isl index 7ad8a0622d4..08248c4ce1b 100644 --- a/build/win32/i18n/messages.it.isl +++ b/build/win32/i18n/messages.it.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Registra %1 come editor per i tipi di file supportati AddToPath=Aggiungi a PATH (disponibile dopo il riavvio) RunAfter=Esegui %1 dopo l'installazione Other=Altro: -SourceFile=File di origine %1 \ No newline at end of file +SourceFile=File di origine %1 +OpenWithCodeContextMenu=Apri con %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.ja.isl b/build/win32/i18n/messages.ja.isl index 3a16aaa204e..9675060e94a 100644 --- a/build/win32/i18n/messages.ja.isl +++ b/build/win32/i18n/messages.ja.isl @@ -5,4 +5,5 @@ AssociateWithFiles= AddToPath=PATH ւ̒ljiċNɎgp”\j RunAfter=CXg[ %1 s Other=̑: -SourceFile=%1 \[X t@C \ No newline at end of file +SourceFile=%1 \[X t@C +OpenWithCodeContextMenu=%1 ŊJ \ No newline at end of file diff --git a/build/win32/i18n/messages.ko.isl b/build/win32/i18n/messages.ko.isl index 28860c36b63..5a510558bbd 100644 --- a/build/win32/i18n/messages.ko.isl +++ b/build/win32/i18n/messages.ko.isl @@ -5,4 +5,5 @@ AssociateWithFiles=%1 AddToPath=PATH ߰(ٽ ) RunAfter=ġ %1 Other=Ÿ: -SourceFile=%1 \ No newline at end of file +SourceFile=%1 +OpenWithCodeContextMenu=%1() \ No newline at end of file diff --git a/build/win32/i18n/messages.pt-br.isl b/build/win32/i18n/messages.pt-br.isl index d534637f8b6..e327e8fd1a0 100644 --- a/build/win32/i18n/messages.pt-br.isl +++ b/build/win32/i18n/messages.pt-br.isl @@ -5,4 +5,5 @@ AssociateWithFiles=Registre %1 como um editor para tipos de arquivos suportados AddToPath=Adicione em PATH (disponvel aps reiniciar) RunAfter=Executar %1 aps a instalao Other=Outros: -SourceFile=Arquivo Fonte %1 \ No newline at end of file +SourceFile=Arquivo Fonte %1 +OpenWithCodeContextMenu=Abrir com %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.ru.isl b/build/win32/i18n/messages.ru.isl index 4d834663627..bca3b864a5f 100644 --- a/build/win32/i18n/messages.ru.isl +++ b/build/win32/i18n/messages.ru.isl @@ -5,4 +5,5 @@ AssociateWithFiles= AddToPath= PATH ( ) RunAfter= %1 Other=: -SourceFile= %1 \ No newline at end of file +SourceFile= %1 +OpenWithCodeContextMenu= %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.tr.isl b/build/win32/i18n/messages.tr.isl index dc241d924c7..b13e5e27bd2 100644 --- a/build/win32/i18n/messages.tr.isl +++ b/build/win32/i18n/messages.tr.isl @@ -5,4 +5,5 @@ AssociateWithFiles=%1 uygulamas AddToPath=PATH'e ekle (yeniden balattktan sonra kullanlabilir) RunAfter=Kurulumdan sonra %1 uygulamasn altr. Other=Dier: -SourceFile=%1 Kaynak Dosyas \ No newline at end of file +SourceFile=%1 Kaynak Dosyas +OpenWithCodeContextMenu=%1 le A \ No newline at end of file diff --git a/build/win32/i18n/messages.zh-cn.isl b/build/win32/i18n/messages.zh-cn.isl index 349fc2ccc29..8fa136f6d5a 100644 --- a/build/win32/i18n/messages.zh-cn.isl +++ b/build/win32/i18n/messages.zh-cn.isl @@ -5,4 +5,5 @@ AssociateWithFiles= AddToPath=ӵ PATH (Ч) RunAfter=װ %1 Other=: -SourceFile=%1 Դļ \ No newline at end of file +SourceFile=%1 Դļ +OpenWithCodeContextMenu=ͨ %1 \ No newline at end of file diff --git a/build/win32/i18n/messages.zh-tw.isl b/build/win32/i18n/messages.zh-tw.isl index 7c3f84aa131..40c5fa92d79 100644 --- a/build/win32/i18n/messages.zh-tw.isl +++ b/build/win32/i18n/messages.zh-tw.isl @@ -5,4 +5,5 @@ AssociateWithFiles= AddToPath=[J PATH (sҰʫͮ) RunAfter=w˫ %1 Other=L: -SourceFile=%1 ӷɮ \ No newline at end of file +SourceFile=%1 ӷɮ +OpenWithCodeContextMenu=H %1 } \ No newline at end of file diff --git a/extensions/cpp/cgmanifest.json b/extensions/cpp/cgmanifest.json index 3dc984e58c2..4fba38d93ad 100644 --- a/extensions/cpp/cgmanifest.json +++ b/extensions/cpp/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "jeff-hykin/cpp-textmate-grammar", "repositoryUrl": "https://github.com/jeff-hykin/cpp-textmate-grammar", - "commitHash": "d937b80a19706d518e5fe52357d7c50d34a26e60" + "commitHash": "fedd206d1b2803f31a278e9b5f098ce4bc76e532" } }, "license": "MIT", - "version": "1.14.11", + "version": "1.14.13", "description": "The files syntaxes/c.json and syntaxes/c++.json were derived from https://github.com/atom/language-c which was originally converted from the C TextMate bundle https://github.com/textmate/c.tmbundle." }, { diff --git a/extensions/cpp/syntaxes/c.tmLanguage.json b/extensions/cpp/syntaxes/c.tmLanguage.json index d8c4dca256b..916371903fb 100644 --- a/extensions/cpp/syntaxes/c.tmLanguage.json +++ b/extensions/cpp/syntaxes/c.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/d937b80a19706d518e5fe52357d7c50d34a26e60", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/fedd206d1b2803f31a278e9b5f098ce4bc76e532", "name": "C", "scopeName": "source.c", "patterns": [ @@ -1177,7 +1177,7 @@ ] }, "member_access": { - "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:atomic_uint_least64_t|atomic_uint_least16_t|atomic_uint_least32_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_fast64_t|atomic_uint_fast32_t|atomic_int_least64_t|atomic_int_least32_t|pthread_rwlockattr_t|atomic_uint_fast16_t|pthread_mutexattr_t|atomic_int_fast16_t|atomic_uint_fast8_t|atomic_int_fast64_t|atomic_int_least8_t|atomic_int_fast32_t|atomic_int_fast8_t|pthread_condattr_t|atomic_uintptr_t|atomic_ptrdiff_t|pthread_rwlock_t|atomic_uintmax_t|pthread_mutex_t|atomic_intmax_t|atomic_intptr_t|atomic_char32_t|atomic_char16_t|pthread_attr_t|atomic_wchar_t|uint_least64_t|uint_least32_t|uint_least16_t|pthread_cond_t|pthread_once_t|uint_fast64_t|uint_fast16_t|atomic_size_t|uint_least8_t|int_least64_t|int_least32_t|int_least16_t|pthread_key_t|atomic_ullong|atomic_ushort|uint_fast32_t|atomic_schar|atomic_short|uint_fast8_t|int_fast64_t|int_fast32_t|int_fast16_t|atomic_ulong|atomic_llong|int_least8_t|atomic_uchar|memory_order|suseconds_t|int_fast8_t|atomic_bool|atomic_char|atomic_uint|atomic_long|atomic_int|useconds_t|_Imaginary|uintptr_t|pthread_t|in_addr_t|blksize_t|in_port_t|uintmax_t|uintmax_t|blkcnt_t|uint16_t|unsigned|_Complex|uint32_t|intptr_t|intmax_t|intmax_t|uint64_t|u_quad_t|int64_t|int32_t|ssize_t|caddr_t|clock_t|uint8_t|u_short|swblk_t|segsz_t|int16_t|fixpt_t|daddr_t|nlink_t|qaddr_t|size_t|time_t|mode_t|signed|quad_t|ushort|u_long|u_char|double|int8_t|ino_t|uid_t|pid_t|_Bool|float|dev_t|div_t|short|gid_t|off_t|u_int|key_t|id_t|uint|long|void|char|bool|id_t|int)\\b)[a-zA-Z_]\\w*\\b(?!\\())", + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:atomic_uint_least64_t|atomic_uint_least16_t|atomic_uint_least32_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_fast64_t|atomic_uint_fast32_t|atomic_int_least64_t|atomic_int_least32_t|pthread_rwlockattr_t|atomic_uint_fast16_t|pthread_mutexattr_t|atomic_int_fast16_t|atomic_uint_fast8_t|atomic_int_fast64_t|atomic_int_least8_t|atomic_int_fast32_t|atomic_int_fast8_t|pthread_condattr_t|atomic_uintptr_t|atomic_ptrdiff_t|pthread_rwlock_t|atomic_uintmax_t|pthread_mutex_t|atomic_intmax_t|atomic_intptr_t|atomic_char32_t|atomic_char16_t|pthread_attr_t|atomic_wchar_t|uint_least64_t|uint_least32_t|uint_least16_t|pthread_cond_t|pthread_once_t|uint_fast64_t|uint_fast16_t|atomic_size_t|uint_least8_t|int_least64_t|int_least32_t|int_least16_t|pthread_key_t|atomic_ullong|atomic_ushort|uint_fast32_t|atomic_schar|atomic_short|uint_fast8_t|int_fast64_t|int_fast32_t|int_fast16_t|atomic_ulong|atomic_llong|int_least8_t|atomic_uchar|memory_order|suseconds_t|int_fast8_t|atomic_bool|atomic_char|atomic_uint|atomic_long|atomic_int|useconds_t|_Imaginary|blksize_t|pthread_t|in_addr_t|uintptr_t|in_port_t|uintmax_t|uintmax_t|blkcnt_t|uint16_t|unsigned|_Complex|uint32_t|intptr_t|intmax_t|intmax_t|uint64_t|u_quad_t|int64_t|int32_t|ssize_t|caddr_t|clock_t|uint8_t|u_short|swblk_t|segsz_t|int16_t|fixpt_t|daddr_t|nlink_t|qaddr_t|size_t|time_t|mode_t|signed|quad_t|ushort|u_long|u_char|double|int8_t|ino_t|uid_t|pid_t|_Bool|float|dev_t|div_t|short|gid_t|off_t|u_int|key_t|id_t|uint|long|void|char|bool|id_t|int)\\b)[a-zA-Z_]\\w*\\b(?!\\())", "captures": { "1": { "name": "variable.other.object.access.c" diff --git a/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json b/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json index cd2400f2c25..3f19e1339cd 100644 --- a/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json +++ b/extensions/cpp/syntaxes/cpp.embedded.macro.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/d937b80a19706d518e5fe52357d7c50d34a26e60", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/fedd206d1b2803f31a278e9b5f098ce4bc76e532", "name": "C++", "scopeName": "source.cpp.embedded.macro", "patterns": [ @@ -966,7 +966,7 @@ ] }, "class_declare": { - "match": "(class)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.class.declare.cpp" @@ -1733,7 +1733,7 @@ }, "constructor_root": { "name": "meta.function.definition.special.constructor.cpp", - "begin": "(\\s*+((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\16((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", + "begin": "(\\s*+((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\16((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", "beginCaptures": { "1": { "name": "meta.head.function.definition.special.constructor.cpp" @@ -2094,7 +2094,7 @@ ] }, "control_flow_keywords": { - "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", "beginCaptures": { "1": { "name": "meta.qualified_type.cpp", @@ -2773,7 +2773,7 @@ }, "destructor_root": { "name": "meta.function.definition.special.member.destructor.cpp", - "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\16((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<14>?)+)>)\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\16((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", "beginCaptures": { "1": { "name": "meta.head.function.definition.special.member.destructor.cpp" @@ -3179,7 +3179,7 @@ }, "enum_block": { "name": "meta.block.enum.cpp", - "begin": "(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?(::))?\\s*((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<15>?)+)>)\\s*)?(::))?\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.enum.declare.cpp" @@ -3859,7 +3859,7 @@ ] }, "function_call": { - "begin": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?(\\()", + "begin": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(((?(?:(?>[^<>]*)\\g<12>?)+)>)\\s*)?(\\()", "beginCaptures": { "1": { "patterns": [ @@ -3933,7 +3933,7 @@ }, "function_definition": { "name": "meta.function.definition.cpp", - "begin": "((?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\())", + "begin": "((?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<70>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\())", "beginCaptures": { "1": { "name": "meta.head.function.definition.cpp" @@ -4529,7 +4529,7 @@ ] }, "function_pointer": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", "beginCaptures": { "1": { "name": "meta.qualified_type.cpp", @@ -4881,7 +4881,7 @@ ] }, "function_pointer_parameter": { - "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", "beginCaptures": { "1": { "name": "meta.qualified_type.cpp", @@ -5535,7 +5535,7 @@ "name": "storage.type.modifier.virtual.cpp" }, { - "match": "(?<=protected|virtual|private|public|,|:)\\s*(?!(?:(?:protected|private|public)|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))", + "match": "(?<=protected|virtual|private|public|,|:)\\s*(?!(?:(?:protected|private|public)|virtual))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -6668,7 +6668,7 @@ ] }, "namespace_alias": { - "match": "(?(?:(?>[^<>]*)\\g<9>?)+)>)\\s*)?::)*\\s*+)\\s*((?(?:(?>[^<>]*)\\g<9>?)+)>)\\s*)?::)*\\s*+)\\s*((?(?:(?>[^<>]*)\\g<5>?)+)>)\\s*)?::)*\\s*+)\\s*((?(?:(?>[^<>]*)\\g<5>?)+)>)\\s*)?::)*\\s*+)\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(?:(?:((?:delete\\[\\]|delete|new\\[\\]|<=>|<<=|new|>>=|\\->\\*|\\/=|%=|&=|>=|\\|=|\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|<<|>>|\\-\\-|<=|\\^=|==|!=|&&|\\|\\||\\+=|\\-=|\\*=|,|\\+|\\-|!|~|\\*|&|\\*|\\/|%|\\+|\\-|<|>|&|\\^|\\||=))|((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\<|\\())", + "begin": "((?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<67>?)+)>)\\s*)?::)*)(?:(?:((?:delete\\[\\]|delete|new\\[\\]|<=>|<<=|new|>>=|\\->\\*|\\/=|%=|&=|>=|\\|=|\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|<<|>>|\\-\\-|<=|\\^=|==|!=|&&|\\|\\||\\+=|\\-=|\\*=|,|\\+|\\-|!|~|\\*|&|\\*|\\/|%|\\+|\\-|<|>|&|\\^|\\||=))|((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\<|\\())", "beginCaptures": { "1": { "name": "meta.head.function.definition.special.operator-overload.cpp" @@ -10607,7 +10607,7 @@ } }, "qualified_type": { - "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(?![\\w<:.])", + "match": "\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<26>?)+)>)\\s*)?(?![\\w<:.])", "captures": { "0": { "name": "meta.qualified_type.cpp", @@ -10810,7 +10810,7 @@ } }, "scope_resolution": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -10833,7 +10833,7 @@ } }, "scope_resolution_function_call": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -10856,7 +10856,7 @@ } }, "scope_resolution_function_call_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -10893,7 +10893,7 @@ } }, "scope_resolution_function_definition": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -10916,7 +10916,7 @@ } }, "scope_resolution_function_definition_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -10953,7 +10953,7 @@ } }, "scope_resolution_function_definition_operator_overload": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -10976,7 +10976,7 @@ } }, "scope_resolution_function_definition_operator_overload_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11013,7 +11013,7 @@ } }, "scope_resolution_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11050,7 +11050,7 @@ } }, "scope_resolution_namespace_alias": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11073,7 +11073,7 @@ } }, "scope_resolution_namespace_alias_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11110,7 +11110,7 @@ } }, "scope_resolution_namespace_block": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11133,7 +11133,7 @@ } }, "scope_resolution_namespace_block_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11170,7 +11170,7 @@ } }, "scope_resolution_namespace_using": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11193,7 +11193,7 @@ } }, "scope_resolution_namespace_using_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11230,7 +11230,7 @@ } }, "scope_resolution_parameter": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11253,7 +11253,7 @@ } }, "scope_resolution_parameter_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11290,7 +11290,7 @@ } }, "scope_resolution_template_call": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11313,7 +11313,7 @@ } }, "scope_resolution_template_call_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11350,7 +11350,7 @@ } }, "scope_resolution_template_definition": { - "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", + "match": "(::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<4>?)+)>)\\s*)?::)*\\s*+", "captures": { "0": { "patterns": [ @@ -11373,7 +11373,7 @@ } }, "scope_resolution_template_definition_inner_generated": { - "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", + "match": "((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<8>?)+)>)\\s*)?(::)", "captures": { "1": { "patterns": [ @@ -11414,7 +11414,7 @@ "name": "punctuation.terminator.statement.cpp" }, "simple_type": { - "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", + "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", "captures": { "1": { "name": "meta.qualified_type.cpp", @@ -12450,7 +12450,7 @@ ] }, "struct_declare": { - "match": "(struct)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.struct.declare.cpp" @@ -13126,7 +13126,7 @@ } }, "type_alias": { - "match": "(using)\\s*(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))\\s*(\\=)\\s*((?:typename)?)\\s*((?:(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))|(.*(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:(\\[)(\\w*)(\\])\\s*)?\\s*(?:(;)|\\n)", + "match": "(using)\\s*(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))\\s*(\\=)\\s*((?:typename)?)\\s*((?:(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<58>?)+)>)\\s*)?(?![\\w<:.]))|(.*(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:(\\[)(\\w*)(\\])\\s*)?\\s*(?:(;)|\\n)", "captures": { "1": { "name": "keyword.other.using.directive.cpp" @@ -14094,7 +14094,7 @@ "end": "(?<=;)|(?=(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<27>?)+)>)\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", "beginCaptures": { "1": { "name": "meta.qualified_type.cpp", @@ -15393,7 +15393,7 @@ ] }, "typename": { - "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|new|try|for|asm|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(?![\\w<:.]))", + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:unsigned|signed|short|long)|(?:struct|class|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((::)?(?:((?-mix:(?!\\b(?:__has_cpp_attribute|reinterpret_cast|atomic_noexcept|atomic_cancel|atomic_commit|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|consteval|constexpr|protected|namespace|co_return|constexpr|constexpr|continue|explicit|volatile|noexcept|co_yield|noexcept|noexcept|requires|typename|decltype|operator|co_await|template|volatile|register|restrict|reflexpr|alignof|private|default|mutable|include|concept|__asm__|defined|_Pragma|alignas|typedef|warning|virtual|mutable|struct|sizeof|delete|not_eq|bitand|and_eq|xor_eq|typeid|switch|return|static|extern|inline|friend|public|ifndef|define|pragma|export|import|module|catch|throw|const|or_eq|while|compl|bitor|const|union|ifdef|class|undef|error|break|using|endif|goto|line|enum|this|case|else|elif|else|asm|try|for|new|and|xor|not|do|or|if|if)\\b)(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:transaction_safe_dynamic|__has_cpp_attribute|transaction_safe|reinterpret_cast|atomic_noexcept|atomic_commit|atomic_cancel|__has_include|dynamic_cast|thread_local|synchronized|static_cast|const_cast|constexpr|consteval|protected|constexpr|co_return|namespace|constexpr|noexcept|typename|decltype|template|operator|noexcept|co_yield|co_await|continue|volatile|register|restrict|explicit|override|volatile|reflexpr|noexcept|requires|default|typedef|nullptr|alignof|mutable|concept|virtual|defined|__asm__|include|_Pragma|mutable|warning|private|alignas|module|switch|not_eq|bitand|and_eq|ifndef|return|sizeof|xor_eq|export|static|delete|public|define|extern|inline|import|pragma|friend|typeid|const|compl|bitor|throw|or_eq|while|catch|break|false|final|const|endif|ifdef|undef|error|using|audit|axiom|line|else|elif|true|NULL|case|goto|else|this|new|asm|not|and|xor|try|for|if|do|or|if)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(((?(?:(?>[^<>]*)\\g<36>?)+)>)\\s*)?(?![\\w<:.]))", "captures": { "1": { "name": "storage.modifier.cpp" @@ -15976,7 +15976,7 @@ ] }, "union_declare": { - "match": "(union)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.union.declare.cpp" @@ -16167,7 +16167,7 @@ }, "using_namespace": { "name": "meta.using-namespace.cpp", - "begin": "(?(?:(?>[^<>]*)\\g<7>?)+)>)\\s*)?::)*\\s*+)?((?(?:(?>[^<>]*)\\g<7>?)+)>)\\s*)?::)*\\s*+)?((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.class.declare.cpp" @@ -3307,7 +3307,7 @@ ] }, "enum_declare": { - "match": "(enum)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.enum.declare.cpp" @@ -12450,7 +12450,7 @@ ] }, "struct_declare": { - "match": "(struct)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.struct.declare.cpp" @@ -15976,7 +15976,7 @@ ] }, "union_declare": { - "match": "(union)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", + "match": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!override\\W|override\\$|final\\W|final\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?![:{])", "captures": { "1": { "name": "storage.type.union.declare.cpp" diff --git a/extensions/git/package.json b/extensions/git/package.json index 060b6af554e..eff48607109 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -1765,7 +1765,7 @@ "byline": "^5.0.0", "file-type": "^7.2.0", "iconv-lite": "^0.4.24", - "jschardet": "^1.6.0", + "jschardet": "2.1.1", "vscode-extension-telemetry": "0.1.1", "vscode-nls": "^4.0.0", "vscode-uri": "^2.0.0", diff --git a/extensions/git/src/encoding.ts b/extensions/git/src/encoding.ts index 92f6edc12a8..ff3eddd8413 100644 --- a/extensions/git/src/encoding.ts +++ b/extensions/git/src/encoding.ts @@ -5,8 +5,6 @@ import * as jschardet from 'jschardet'; -jschardet.Constants.MINIMUM_THRESHOLD = 0.2; - function detectEncodingByBOM(buffer: Buffer): string | null { if (!buffer || buffer.length < 2) { return null; diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 6d54fb4db21..a710a539c29 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -1819,8 +1819,11 @@ export class Repository { } // Else, remove all lines starting with whitespace followed by `#`. - //TODO: Support core.commentChar - return message.replace(/^\s*#.*$\n?/gm, '').trim(); + // TODO: Support core.commentChar + return message.replace(/^(\s*#)(.*)$(\n?)/gm, (_, prefix, content, suffix) => { + // https://github.com/microsoft/vscode/issues/84201#issuecomment-552834814 + return /^\d/.test(content) ? `${prefix}${content}${suffix}` : ''; + }).trim(); } async getMergeMessage(): Promise { diff --git a/extensions/git/src/typings/jschardet.d.ts b/extensions/git/src/typings/jschardet.d.ts deleted file mode 100644 index f252a47fd09..00000000000 --- a/extensions/git/src/typings/jschardet.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -declare module 'jschardet' { - export interface IDetectedMap { - encoding: string, - confidence: number - } - export function detect(buffer: Buffer): IDetectedMap; - - export const Constants: { - MINIMUM_THRESHOLD: number, - } -} \ No newline at end of file diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index 2bfd883067d..58a82bbe41c 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -176,10 +176,10 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -jschardet@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" - integrity sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ== +jschardet@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184" + integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q== json3@3.3.2: version "3.3.2" diff --git a/extensions/image-preview/src/preview.ts b/extensions/image-preview/src/preview.ts index 310043c4d37..7b859877304 100644 --- a/extensions/image-preview/src/preview.ts +++ b/extensions/image-preview/src/preview.ts @@ -229,8 +229,11 @@ class Preview extends Disposable { // Show blank image return encodeURI('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAEElEQVR42gEFAPr/AP///wAI/AL+Sr4t6gAAAABJRU5ErkJggg=='); - default: + // Avoid adding cache busting if there is already a query string + if (resource.query) { + return encodeURI(webviewEditor.webview.asWebviewUri(resource).toString(true)); + } return encodeURI(webviewEditor.webview.asWebviewUri(resource).toString(true) + `?version=${version}`); } } diff --git a/extensions/markdown-language-features/media/index.js b/extensions/markdown-language-features/media/index.js index 5e5314ae725..1aa7530d341 100644 --- a/extensions/markdown-language-features/media/index.js +++ b/extensions/markdown-language-features/media/index.js @@ -1,2 +1,2 @@ -!function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=2)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});let o=void 0;function i(e){const t=document.getElementById("vscode-markdown-preview-data");if(t){const n=t.getAttribute(e);if(n)return JSON.parse(n)}throw new Error(`Could not load data for ${e}`)}t.getData=i,t.getSettings=function(){if(o)return o;if(o=i("data-settings"))return o;throw new Error("Could not load settings")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(0);function i(e){return t=0,n=o.getSettings().lineCount-1,i=e,Math.min(n,Math.max(t,i));var t,n,i}const r=(()=>{let e;return()=>{if(!e){e=[{element:document.body,line:0}];for(const t of document.getElementsByClassName("code-line")){const n=+t.getAttribute("data-line");isNaN(n)||("CODE"===t.tagName&&t.parentElement&&"PRE"===t.parentElement.tagName?e.push({element:t.parentElement,line:n}):e.push({element:t,line:n}))}}return e}})();function s(e){const t=Math.floor(e),n=r();let o=n[0]||null;for(const e of n){if(e.line===t)return{previous:e,next:void 0};if(e.line>t)return{previous:o,next:e};o=e}return{previous:o}}function c(e){const t=r(),n=e-window.scrollY;let o=-1,i=t.length-1;for(;o+1=n?i=e:o=e}const s=t[i],c=s.element.getBoundingClientRect();if(i>=1&&c.top>n){return{previous:t[o],next:s}}return i>1&&in?{previous:s,next:t[i+1]}:{previous:s}}t.getElementsForSourceLine=s,t.getLineElementsAtPageOffset=c,t.scrollToRevealSourceLine=function(e){if(!o.getSettings().scrollPreviewWithEditor)return;if(e<=0)return void window.scroll(window.scrollX,0);const{previous:t,next:n}=s(e);if(!t)return;let i=0;const r=t.element.getBoundingClientRect(),c=r.top;if(n&&n.line!==t.line){i=c+(e-t.line)/(n.line-t.line)*(n.element.getBoundingClientRect().top-c)}else{const t=e-Math.floor(e);i=c+r.height*t}window.scroll(window.scrollX,Math.max(1,window.scrollY+i))},t.getEditorLineNumberForPageOffset=function(e){const{previous:t,next:n}=c(e);if(t){const o=t.element.getBoundingClientRect(),r=e-window.scrollY-o.top;if(n){const e=r/(n.element.getBoundingClientRect().top-o.top);return i(t.line+e*(n.line-t.line))}{const e=r/o.height;return i(t.line+e)}}return null},t.getLineElementForFragment=function(e){return r().find(t=>t.element.id===e)}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(3),i=n(4),r=n(5),s=n(1),c=n(0),a=n(6);let u=!0;const l=new o.ActiveLineMarker,d=c.getSettings(),f=acquireVsCodeApi();let g=c.getData("data-state");f.setState(g);const p=r.createPosterForVsCode(f);window.cspAlerter.setPoster(p),window.styleLoadingMonitor.setPoster(p),window.onload=()=>{v()},i.onceDocumentLoaded(()=>{d.scrollPreviewWithEditor&&setTimeout(()=>{if(g.fragment){const e=s.getLineElementForFragment(g.fragment);e&&(u=!0,s.scrollToRevealSourceLine(e.line))}else{const e=+d.line;isNaN(e)||(u=!0,s.scrollToRevealSourceLine(e))}},0)});const m=(()=>{const e=a(e=>{u=!0,s.scrollToRevealSourceLine(e)},50);return(t,n)=>{isNaN(t)||(n.line=t,e(t))}})();let v=a(()=>{const e=[];let t=document.getElementsByTagName("img");if(t){let n;for(n=0;n{u=!0,v()},!0),window.addEventListener("message",e=>{if(e.data.source===d.source)switch(e.data.type){case"onDidChangeTextEditorSelection":l.onDidChangeTextEditorSelection(e.data.line);break;case"updateView":m(e.data.line,d)}},!1),document.addEventListener("dblclick",e=>{if(!d.doubleClickToSwitchToEditor)return;for(let t=e.target;t;t=t.parentNode)if("A"===t.tagName)return;const t=e.pageY,n=s.getEditorLineNumberForPageOffset(t);"number"!=typeof n||isNaN(n)||p.postMessage("didClick",{line:Math.floor(n)})});const h=["http:","https:","mailto:","vscode:","vscode-insiders:"];document.addEventListener("click",e=>{if(!e)return;let t=e.target;for(;t;){if(t.tagName&&"A"===t.tagName&&t.href){if(t.getAttribute("href").startsWith("#"))return;if(h.some(e=>t.href.startsWith(e)))return;const n=t.getAttribute("data-href")||t.getAttribute("href");return/^[a-z\-]+:/i.test(n)?void 0:(p.postMessage("openLink",{href:n}),e.preventDefault(),void e.stopPropagation())}t=t.parentNode}},!0),window.addEventListener("scroll",a(()=>{if(u)u=!1;else{const e=s.getEditorLineNumberForPageOffset(window.scrollY);"number"!=typeof e||isNaN(e)||(p.postMessage("revealLine",{line:e}),g.line=e,f.setState(g))}},50))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(1);t.ActiveLineMarker=class{onDidChangeTextEditorSelection(e){const{previous:t}=o.getElementsForSourceLine(e);this._update(t&&t.element)}_update(e){this._unmarkActiveElement(this._current),this._markActiveElement(e),this._current=e}_unmarkActiveElement(e){e&&(e.className=e.className.replace(/\bcode-active-line\b/g,""))}_markActiveElement(e){e&&(e.className+=" code-active-line")}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.onceDocumentLoaded=function(e){"loading"===document.readyState||"uninitialized"===document.readyState?document.addEventListener("DOMContentLoaded",e):e()}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(0);t.createPosterForVsCode=e=>new class{postMessage(t,n){e.postMessage({type:t,source:o.getSettings().source,body:n})}}},function(e,t,n){(function(t){var n="Expected a function",o=NaN,i="[object Symbol]",r=/^\s+|\s+$/g,s=/^[-+]0x[0-9a-f]+$/i,c=/^0b[01]+$/i,a=/^0o[0-7]+$/i,u=parseInt,l="object"==typeof t&&t&&t.Object===Object&&t,d="object"==typeof self&&self&&self.Object===Object&&self,f=l||d||Function("return this")(),g=Object.prototype.toString,p=Math.max,m=Math.min,v=function(){return f.Date.now()};function h(e,t,o){var i,r,s,c,a,u,l=0,d=!1,f=!1,g=!0;if("function"!=typeof e)throw new TypeError(n);function h(t){var n=i,o=r;return i=r=void 0,l=t,c=e.apply(o,n)}function y(e){var n=e-u;return void 0===u||n>=t||n<0||f&&e-l>=s}function E(){var e=v();if(y(e))return M(e);a=setTimeout(E,function(e){var n=t-(e-u);return f?m(n,s-(e-l)):n}(e))}function M(e){return a=void 0,g&&i?h(e):(i=r=void 0,c)}function L(){var e=v(),n=y(e);if(i=arguments,r=this,u=e,n){if(void 0===a)return function(e){return l=e,a=setTimeout(E,t),d?h(e):c}(u);if(f)return a=setTimeout(E,t),h(u)}return void 0===a&&(a=setTimeout(E,t)),c}return t=b(t)||0,w(o)&&(d=!!o.leading,s=(f="maxWait"in o)?p(b(o.maxWait)||0,t):s,g="trailing"in o?!!o.trailing:g),L.cancel=function(){void 0!==a&&clearTimeout(a),l=0,i=u=r=a=void 0},L.flush=function(){return void 0===a?c:M(v())},L}function w(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function b(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&g.call(e)==i}(e))return o;if(w(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=w(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(r,"");var n=c.test(e);return n||a.test(e)?u(e.slice(2),n?2:8):s.test(e)?o:+e}e.exports=function(e,t,o){var i=!0,r=!0;if("function"!=typeof e)throw new TypeError(n);return w(o)&&(i="leading"in o?!!o.leading:i,r="trailing"in o?!!o.trailing:r),h(e,t,{leading:i,maxWait:t,trailing:r})}}).call(this,n(7))},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n}]); -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvc2V0dGluZ3MudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvc2Nyb2xsLXN5bmMudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvYWN0aXZlTGluZU1hcmtlci50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9ldmVudHMudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvbWVzc2FnaW5nLnRzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9sb2Rhc2gudGhyb3R0bGUvaW5kZXguanMiLCJ3ZWJwYWNrOi8vLyh3ZWJwYWNrKS9idWlsZGluL2dsb2JhbC5qcyJdLCJuYW1lcyI6WyJpbnN0YWxsZWRNb2R1bGVzIiwiX193ZWJwYWNrX3JlcXVpcmVfXyIsIm1vZHVsZUlkIiwiZXhwb3J0cyIsIm1vZHVsZSIsImkiLCJsIiwibW9kdWxlcyIsImNhbGwiLCJtIiwiYyIsImQiLCJuYW1lIiwiZ2V0dGVyIiwibyIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZW51bWVyYWJsZSIsImdldCIsInIiLCJTeW1ib2wiLCJ0b1N0cmluZ1RhZyIsInZhbHVlIiwidCIsIm1vZGUiLCJfX2VzTW9kdWxlIiwibnMiLCJjcmVhdGUiLCJrZXkiLCJiaW5kIiwibiIsIm9iamVjdCIsInByb3BlcnR5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJwIiwicyIsImNhY2hlZFNldHRpbmdzIiwidW5kZWZpbmVkIiwiZ2V0RGF0YSIsImVsZW1lbnQiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwiZGF0YSIsImdldEF0dHJpYnV0ZSIsIkpTT04iLCJwYXJzZSIsIkVycm9yIiwiZ2V0U2V0dGluZ3MiLCJzZXR0aW5nc18xIiwiY2xhbXBMaW5lIiwibGluZSIsIm1pbiIsIm1heCIsImxpbmVDb3VudCIsIk1hdGgiLCJnZXRDb2RlTGluZUVsZW1lbnRzIiwiZWxlbWVudHMiLCJib2R5IiwiZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSIsImlzTmFOIiwidGFnTmFtZSIsInBhcmVudEVsZW1lbnQiLCJwdXNoIiwiZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lIiwidGFyZ2V0TGluZSIsImxpbmVOdW1iZXIiLCJmbG9vciIsImxpbmVzIiwicHJldmlvdXMiLCJlbnRyeSIsIm5leHQiLCJnZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQiLCJvZmZzZXQiLCJwb3NpdGlvbiIsIndpbmRvdyIsInNjcm9sbFkiLCJsbyIsImhpIiwibGVuZ3RoIiwibWlkIiwiYm91bmRzIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidG9wIiwiaGVpZ2h0IiwiaGlFbGVtZW50IiwiaGlCb3VuZHMiLCJzY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUiLCJzY3JvbGxQcmV2aWV3V2l0aEVkaXRvciIsInNjcm9sbCIsInNjcm9sbFgiLCJzY3JvbGxUbyIsInJlY3QiLCJwcmV2aW91c1RvcCIsInByb2dyZXNzSW5FbGVtZW50IiwiZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQiLCJwcmV2aW91c0JvdW5kcyIsIm9mZnNldEZyb21QcmV2aW91cyIsInByb2dyZXNzQmV0d2VlbkVsZW1lbnRzIiwicHJvZ3Jlc3NXaXRoaW5FbGVtZW50IiwiZ2V0TGluZUVsZW1lbnRGb3JGcmFnbWVudCIsImZyYWdtZW50IiwiZmluZCIsImlkIiwiYWN0aXZlTGluZU1hcmtlcl8xIiwiZXZlbnRzXzEiLCJtZXNzYWdpbmdfMSIsInNjcm9sbF9zeW5jXzEiLCJ0aHJvdHRsZSIsInNjcm9sbERpc2FibGVkIiwibWFya2VyIiwiQWN0aXZlTGluZU1hcmtlciIsInNldHRpbmdzIiwidnNjb2RlIiwiYWNxdWlyZVZzQ29kZUFwaSIsInN0YXRlIiwic2V0U3RhdGUiLCJtZXNzYWdpbmciLCJjcmVhdGVQb3N0ZXJGb3JWc0NvZGUiLCJjc3BBbGVydGVyIiwic2V0UG9zdGVyIiwic3R5bGVMb2FkaW5nTW9uaXRvciIsIm9ubG9hZCIsInVwZGF0ZUltYWdlU2l6ZXMiLCJvbmNlRG9jdW1lbnRMb2FkZWQiLCJzZXRUaW1lb3V0IiwiaW5pdGlhbExpbmUiLCJvblVwZGF0ZVZpZXciLCJkb1Njcm9sbCIsImltYWdlSW5mbyIsImltYWdlcyIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwiaW1nIiwiY2xhc3NMaXN0IiwiY29udGFpbnMiLCJyZW1vdmUiLCJ3aWR0aCIsInBvc3RNZXNzYWdlIiwiYWRkRXZlbnRMaXN0ZW5lciIsImV2ZW50Iiwic291cmNlIiwidHlwZSIsIm9uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbiIsImRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvciIsIm5vZGUiLCJ0YXJnZXQiLCJwYXJlbnROb2RlIiwicGFnZVkiLCJwYXNzVGhyb3VnaExpbmtTY2hlbWVzIiwiaHJlZiIsInN0YXJ0c1dpdGgiLCJzb21lIiwic2NoZW1lIiwiaHJlZlRleHQiLCJ0ZXN0IiwicHJldmVudERlZmF1bHQiLCJzdG9wUHJvcGFnYXRpb24iLCJ0aGlzIiwiX3VwZGF0ZSIsImJlZm9yZSIsIl91bm1hcmtBY3RpdmVFbGVtZW50IiwiX2N1cnJlbnQiLCJfbWFya0FjdGl2ZUVsZW1lbnQiLCJjbGFzc05hbWUiLCJyZXBsYWNlIiwiZiIsInJlYWR5U3RhdGUiLCJGVU5DX0VSUk9SX1RFWFQiLCJOQU4iLCJzeW1ib2xUYWciLCJyZVRyaW0iLCJyZUlzQmFkSGV4IiwicmVJc0JpbmFyeSIsInJlSXNPY3RhbCIsImZyZWVQYXJzZUludCIsInBhcnNlSW50IiwiZnJlZUdsb2JhbCIsImdsb2JhbCIsImZyZWVTZWxmIiwic2VsZiIsInJvb3QiLCJGdW5jdGlvbiIsIm9iamVjdFRvU3RyaW5nIiwidG9TdHJpbmciLCJuYXRpdmVNYXgiLCJuYXRpdmVNaW4iLCJub3ciLCJEYXRlIiwiZGVib3VuY2UiLCJmdW5jIiwid2FpdCIsIm9wdGlvbnMiLCJsYXN0QXJncyIsImxhc3RUaGlzIiwibWF4V2FpdCIsInJlc3VsdCIsInRpbWVySWQiLCJsYXN0Q2FsbFRpbWUiLCJsYXN0SW52b2tlVGltZSIsImxlYWRpbmciLCJtYXhpbmciLCJ0cmFpbGluZyIsIlR5cGVFcnJvciIsImludm9rZUZ1bmMiLCJ0aW1lIiwiYXJncyIsInRoaXNBcmciLCJhcHBseSIsInNob3VsZEludm9rZSIsInRpbWVTaW5jZUxhc3RDYWxsIiwidGltZXJFeHBpcmVkIiwidHJhaWxpbmdFZGdlIiwicmVtYWluaW5nV2FpdCIsImRlYm91bmNlZCIsImlzSW52b2tpbmciLCJhcmd1bWVudHMiLCJsZWFkaW5nRWRnZSIsInRvTnVtYmVyIiwiaXNPYmplY3QiLCJjYW5jZWwiLCJjbGVhclRpbWVvdXQiLCJmbHVzaCIsImlzT2JqZWN0TGlrZSIsImlzU3ltYm9sIiwib3RoZXIiLCJ2YWx1ZU9mIiwiaXNCaW5hcnkiLCJzbGljZSIsImciLCJlIl0sIm1hcHBpbmdzIjoiYUFDRSxJQUFJQSxFQUFtQixHQUd2QixTQUFTQyxFQUFvQkMsR0FHNUIsR0FBR0YsRUFBaUJFLEdBQ25CLE9BQU9GLEVBQWlCRSxHQUFVQyxRQUduQyxJQUFJQyxFQUFTSixFQUFpQkUsR0FBWSxDQUN6Q0csRUFBR0gsRUFDSEksR0FBRyxFQUNISCxRQUFTLElBVVYsT0FOQUksRUFBUUwsR0FBVU0sS0FBS0osRUFBT0QsUUFBU0MsRUFBUUEsRUFBT0QsUUFBU0YsR0FHL0RHLEVBQU9FLEdBQUksRUFHSkYsRUFBT0QsUUFLZkYsRUFBb0JRLEVBQUlGLEVBR3hCTixFQUFvQlMsRUFBSVYsRUFHeEJDLEVBQW9CVSxFQUFJLFNBQVNSLEVBQVNTLEVBQU1DLEdBQzNDWixFQUFvQmEsRUFBRVgsRUFBU1MsSUFDbENHLE9BQU9DLGVBQWViLEVBQVNTLEVBQU0sQ0FBRUssWUFBWSxFQUFNQyxJQUFLTCxLQUtoRVosRUFBb0JrQixFQUFJLFNBQVNoQixHQUNYLG9CQUFYaUIsUUFBMEJBLE9BQU9DLGFBQzFDTixPQUFPQyxlQUFlYixFQUFTaUIsT0FBT0MsWUFBYSxDQUFFQyxNQUFPLFdBRTdEUCxPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sS0FRdkRyQixFQUFvQnNCLEVBQUksU0FBU0QsRUFBT0UsR0FFdkMsR0FEVSxFQUFQQSxJQUFVRixFQUFRckIsRUFBb0JxQixJQUMvQixFQUFQRSxFQUFVLE9BQU9GLEVBQ3BCLEdBQVcsRUFBUEUsR0FBOEIsaUJBQVZGLEdBQXNCQSxHQUFTQSxFQUFNRyxXQUFZLE9BQU9ILEVBQ2hGLElBQUlJLEVBQUtYLE9BQU9ZLE9BQU8sTUFHdkIsR0FGQTFCLEVBQW9Ca0IsRUFBRU8sR0FDdEJYLE9BQU9DLGVBQWVVLEVBQUksVUFBVyxDQUFFVCxZQUFZLEVBQU1LLE1BQU9BLElBQ3RELEVBQVBFLEdBQTRCLGlCQUFURixFQUFtQixJQUFJLElBQUlNLEtBQU9OLEVBQU9yQixFQUFvQlUsRUFBRWUsRUFBSUUsRUFBSyxTQUFTQSxHQUFPLE9BQU9OLEVBQU1NLElBQVFDLEtBQUssS0FBTUQsSUFDOUksT0FBT0YsR0FJUnpCLEVBQW9CNkIsRUFBSSxTQUFTMUIsR0FDaEMsSUFBSVMsRUFBU1QsR0FBVUEsRUFBT3FCLFdBQzdCLFdBQXdCLE9BQU9yQixFQUFnQixTQUMvQyxXQUE4QixPQUFPQSxHQUV0QyxPQURBSCxFQUFvQlUsRUFBRUUsRUFBUSxJQUFLQSxHQUM1QkEsR0FJUlosRUFBb0JhLEVBQUksU0FBU2lCLEVBQVFDLEdBQVksT0FBT2pCLE9BQU9rQixVQUFVQyxlQUFlMUIsS0FBS3VCLEVBQVFDLElBR3pHL0IsRUFBb0JrQyxFQUFJLEdBSWpCbEMsRUFBb0JBLEVBQW9CbUMsRUFBSSxHLCtCQzdFckRyQixPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sSUFDdEQsSUFBSWUsT0FBaUJDLEVBQ3JCLFNBQVNDLEVBQVFYLEdBQ2IsTUFBTVksRUFBVUMsU0FBU0MsZUFBZSxnQ0FDeEMsR0FBSUYsRUFBUyxDQUNULE1BQU1HLEVBQU9ILEVBQVFJLGFBQWFoQixHQUNsQyxHQUFJZSxFQUNBLE9BQU9FLEtBQUtDLE1BQU1ILEdBRzFCLE1BQU0sSUFBSUksTUFBTSwyQkFBMkJuQixLQUUvQ3pCLEVBQVFvQyxRQUFVQSxFQVdsQnBDLEVBQVE2QyxZQVZSLFdBQ0ksR0FBSVgsRUFDQSxPQUFPQSxFQUdYLEdBREFBLEVBQWlCRSxFQUFRLGlCQUVyQixPQUFPRixFQUVYLE1BQU0sSUFBSVUsTUFBTSw2Qiw2QkNyQnBCaEMsT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBQ3RELE1BQU0yQixFQUFhLEVBQVEsR0FJM0IsU0FBU0MsRUFBVUMsR0FDZixPQUpXQyxFQUlFLEVBSkdDLEVBSUFKLEVBQVdELGNBQWNNLFVBQVksRUFKaENoQyxFQUltQzZCLEVBSGpESSxLQUFLSCxJQUFJQyxFQUFLRSxLQUFLRixJQUFJRCxFQUFLOUIsSUFEdkMsSUFBZThCLEVBQUtDLEVBQUsvQixFQU16QixNQUFNa0MsRUFBc0IsTUFDeEIsSUFBSUMsRUFDSixNQUFPLEtBQ0gsSUFBS0EsRUFBVSxDQUNYQSxFQUFXLENBQUMsQ0FBRWpCLFFBQVNDLFNBQVNpQixLQUFNUCxLQUFNLElBQzVDLElBQUssTUFBTVgsS0FBV0MsU0FBU2tCLHVCQUF1QixhQUFjLENBQ2hFLE1BQU1SLEdBQVFYLEVBQVFJLGFBQWEsYUFDL0JnQixNQUFNVCxLQUdjLFNBQXBCWCxFQUFRcUIsU0FBc0JyQixFQUFRc0IsZUFBbUQsUUFBbEN0QixFQUFRc0IsY0FBY0QsUUFHN0VKLEVBQVNNLEtBQUssQ0FBRXZCLFFBQVNBLEVBQVFzQixjQUFlWCxTQUdoRE0sRUFBU00sS0FBSyxDQUFFdkIsUUFBU0EsRUFBU1csV0FJOUMsT0FBT00sSUFwQmEsR0E2QjVCLFNBQVNPLEVBQXlCQyxHQUM5QixNQUFNQyxFQUFhWCxLQUFLWSxNQUFNRixHQUN4QkcsRUFBUVosSUFDZCxJQUFJYSxFQUFXRCxFQUFNLElBQU0sS0FDM0IsSUFBSyxNQUFNRSxLQUFTRixFQUFPLENBQ3ZCLEdBQUlFLEVBQU1uQixPQUFTZSxFQUNmLE1BQU8sQ0FBRUcsU0FBVUMsRUFBT0MsVUFBTWpDLEdBRS9CLEdBQUlnQyxFQUFNbkIsS0FBT2UsRUFDbEIsTUFBTyxDQUFFRyxXQUFVRSxLQUFNRCxHQUU3QkQsRUFBV0MsRUFFZixNQUFPLENBQUVELFlBTWIsU0FBU0csRUFBNEJDLEdBQ2pDLE1BQU1MLEVBQVFaLElBQ1JrQixFQUFXRCxFQUFTRSxPQUFPQyxRQUNqQyxJQUFJQyxHQUFNLEVBQ05DLEVBQUtWLEVBQU1XLE9BQVMsRUFDeEIsS0FBT0YsRUFBSyxFQUFJQyxHQUFJLENBQ2hCLE1BQU1FLEVBQU16QixLQUFLWSxPQUFPVSxFQUFLQyxHQUFNLEdBQzdCRyxFQUFTYixFQUFNWSxHQUFLeEMsUUFBUTBDLHdCQUM5QkQsRUFBT0UsSUFBTUYsRUFBT0csUUFBVVYsRUFDOUJJLEVBQUtFLEVBR0xILEVBQUtHLEVBR2IsTUFBTUssRUFBWWpCLEVBQU1VLEdBQ2xCUSxFQUFXRCxFQUFVN0MsUUFBUTBDLHdCQUNuQyxHQUFJSixHQUFNLEdBQUtRLEVBQVNILElBQU1ULEVBQVUsQ0FFcEMsTUFBTyxDQUFFTCxTQURTRCxFQUFNUyxHQUNNTixLQUFNYyxHQUV4QyxPQUFJUCxFQUFLLEdBQUtBLEVBQUtWLEVBQU1XLFFBQVVPLEVBQVNILElBQU1HLEVBQVNGLE9BQVNWLEVBQ3pELENBQUVMLFNBQVVnQixFQUFXZCxLQUFNSCxFQUFNVSxFQUFLLElBRTVDLENBQUVULFNBQVVnQixHQTVCdkJsRixFQUFRNkQseUJBQTJCQSxFQThCbkM3RCxFQUFRcUUsNEJBQThCQSxFQStCdENyRSxFQUFRb0YseUJBM0JSLFNBQWtDcEMsR0FDOUIsSUFBS0YsRUFBV0QsY0FBY3dDLHdCQUMxQixPQUVKLEdBQUlyQyxHQUFRLEVBRVIsWUFEQXdCLE9BQU9jLE9BQU9kLE9BQU9lLFFBQVMsR0FHbEMsTUFBTSxTQUFFckIsRUFBUSxLQUFFRSxHQUFTUCxFQUF5QmIsR0FDcEQsSUFBS2tCLEVBQ0QsT0FFSixJQUFJc0IsRUFBVyxFQUNmLE1BQU1DLEVBQU92QixFQUFTN0IsUUFBUTBDLHdCQUN4QlcsRUFBY0QsRUFBS1QsSUFDekIsR0FBSVosR0FBUUEsRUFBS3BCLE9BQVNrQixFQUFTbEIsS0FBTSxDQUlyQ3dDLEVBQVdFLEdBRmMxQyxFQUFPa0IsRUFBU2xCLE9BQVNvQixFQUFLcEIsS0FBT2tCLEVBQVNsQixPQUNqRG9CLEVBQUsvQixRQUFRMEMsd0JBQXdCQyxJQUFNVSxPQUdoRSxDQUNELE1BQU1DLEVBQW9CM0MsRUFBT0ksS0FBS1ksTUFBTWhCLEdBQzVDd0MsRUFBV0UsRUFBZUQsRUFBS1IsT0FBU1UsRUFFNUNuQixPQUFPYyxPQUFPZCxPQUFPZSxRQUFTbkMsS0FBS0YsSUFBSSxFQUFHc0IsT0FBT0MsUUFBVWUsS0FxQi9EeEYsRUFBUTRGLGlDQWxCUixTQUEwQ3RCLEdBQ3RDLE1BQU0sU0FBRUosRUFBUSxLQUFFRSxHQUFTQyxFQUE0QkMsR0FDdkQsR0FBSUosRUFBVSxDQUNWLE1BQU0yQixFQUFpQjNCLEVBQVM3QixRQUFRMEMsd0JBQ2xDZSxFQUFzQnhCLEVBQVNFLE9BQU9DLFFBQVVvQixFQUFlYixJQUNyRSxHQUFJWixFQUFNLENBQ04sTUFBTTJCLEVBQTBCRCxHQUFzQjFCLEVBQUsvQixRQUFRMEMsd0JBQXdCQyxJQUFNYSxFQUFlYixLQUVoSCxPQUFPakMsRUFETW1CLEVBQVNsQixLQUFPK0MsR0FBMkIzQixFQUFLcEIsS0FBT2tCLEVBQVNsQixPQUc1RSxDQUNELE1BQU1nRCxFQUF3QkYsRUFBc0JELEVBQXFCLE9BRXpFLE9BQU85QyxFQURNbUIsRUFBU2xCLEtBQU9nRCxJQUlyQyxPQUFPLE1BV1hoRyxFQUFRaUcsMEJBTFIsU0FBbUNDLEdBQy9CLE9BQU83QyxJQUFzQjhDLEtBQU05RCxHQUN4QkEsRUFBUUEsUUFBUStELEtBQU9GLEssNkJDMUl0Q3RGLE9BQU9DLGVBQWViLEVBQVMsYUFBYyxDQUFFbUIsT0FBTyxJQUN0RCxNQUFNa0YsRUFBcUIsRUFBUSxHQUM3QkMsRUFBVyxFQUFRLEdBQ25CQyxFQUFjLEVBQVEsR0FDdEJDLEVBQWdCLEVBQVEsR0FDeEIxRCxFQUFhLEVBQVEsR0FDckIyRCxFQUFXLEVBQVEsR0FDekIsSUFBSUMsR0FBaUIsRUFDckIsTUFBTUMsRUFBUyxJQUFJTixFQUFtQk8saUJBQ2hDQyxFQUFXL0QsRUFBV0QsY0FDdEJpRSxFQUFTQyxtQkFFZixJQUFJQyxFQUFRbEUsRUFBV1YsUUFBUSxjQUMvQjBFLEVBQU9HLFNBQVNELEdBQ2hCLE1BQU1FLEVBQVlYLEVBQVlZLHNCQUFzQkwsR0FDcER0QyxPQUFPNEMsV0FBV0MsVUFBVUgsR0FDNUIxQyxPQUFPOEMsb0JBQW9CRCxVQUFVSCxHQUNyQzFDLE9BQU8rQyxPQUFTLEtBQ1pDLEtBRUpsQixFQUFTbUIsbUJBQW1CLEtBQ3BCWixFQUFTeEIseUJBQ1RxQyxXQUFXLEtBRVAsR0FBSVYsRUFBTWQsU0FBVSxDQUNoQixNQUFNN0QsRUFBVW1FLEVBQWNQLDBCQUEwQmUsRUFBTWQsVUFDMUQ3RCxJQUNBcUUsR0FBaUIsRUFDakJGLEVBQWNwQix5QkFBeUIvQyxFQUFRVyxXQUdsRCxDQUNELE1BQU0yRSxHQUFlZCxFQUFTN0QsS0FDekJTLE1BQU1rRSxLQUNQakIsR0FBaUIsRUFDakJGLEVBQWNwQix5QkFBeUJ1QyxNQUdoRCxLQUdYLE1BQU1DLEVBQWUsTUFDakIsTUFBTUMsRUFBV3BCLEVBQVV6RCxJQUN2QjBELEdBQWlCLEVBQ2pCRixFQUFjcEIseUJBQXlCcEMsSUFDeEMsSUFDSCxNQUFPLENBQUNBLEVBQU02RCxLQUNMcEQsTUFBTVQsS0FDUDZELEVBQVM3RCxLQUFPQSxFQUNoQjZFLEVBQVM3RSxNQVJBLEdBWXJCLElBQUl3RSxFQUFtQmYsRUFBUyxLQUM1QixNQUFNcUIsRUFBWSxHQUNsQixJQUFJQyxFQUFTekYsU0FBUzBGLHFCQUFxQixPQUMzQyxHQUFJRCxFQUFRLENBQ1IsSUFBSTdILEVBQ0osSUFBS0EsRUFBSSxFQUFHQSxFQUFJNkgsRUFBT25ELE9BQVExRSxJQUFLLENBQ2hDLE1BQU0rSCxFQUFNRixFQUFPN0gsR0FDZitILEVBQUlDLFVBQVVDLFNBQVMsWUFDdkJGLEVBQUlDLFVBQVVFLE9BQU8sV0FFekJOLEVBQVVsRSxLQUFLLENBQ1h3QyxHQUFJNkIsRUFBSTdCLEdBQ1JuQixPQUFRZ0QsRUFBSWhELE9BQ1pvRCxNQUFPSixFQUFJSSxRQUduQm5CLEVBQVVvQixZQUFZLGtCQUFtQlIsS0FFOUMsSUFDSHRELE9BQU8rRCxpQkFBaUIsU0FBVSxLQUM5QjdCLEdBQWlCLEVBQ2pCYyxNQUNELEdBQ0hoRCxPQUFPK0QsaUJBQWlCLFVBQVdDLElBQy9CLEdBQUlBLEVBQU1oRyxLQUFLaUcsU0FBVzVCLEVBQVM0QixPQUduQyxPQUFRRCxFQUFNaEcsS0FBS2tHLE1BQ2YsSUFBSyxpQ0FDRC9CLEVBQU9nQywrQkFBK0JILEVBQU1oRyxLQUFLUSxNQUNqRCxNQUNKLElBQUssYUFDRDRFLEVBQWFZLEVBQU1oRyxLQUFLUSxLQUFNNkQsTUFHdkMsR0FDSHZFLFNBQVNpRyxpQkFBaUIsV0FBWUMsSUFDbEMsSUFBSzNCLEVBQVMrQiw0QkFDVixPQUdKLElBQUssSUFBSUMsRUFBT0wsRUFBTU0sT0FBUUQsRUFBTUEsRUFBT0EsRUFBS0UsV0FDNUMsR0FBcUIsTUFBakJGLEVBQUtuRixRQUNMLE9BR1IsTUFBTVksRUFBU2tFLEVBQU1RLE1BQ2ZoRyxFQUFPd0QsRUFBY1osaUNBQWlDdEIsR0FDeEMsaUJBQVR0QixHQUFzQlMsTUFBTVQsSUFDbkNrRSxFQUFVb0IsWUFBWSxXQUFZLENBQUV0RixLQUFNSSxLQUFLWSxNQUFNaEIsT0FHN0QsTUFBTWlHLEVBQXlCLENBQUMsUUFBUyxTQUFVLFVBQVcsVUFBVyxvQkFDekUzRyxTQUFTaUcsaUJBQWlCLFFBQVNDLElBQy9CLElBQUtBLEVBQ0QsT0FFSixJQUFJSyxFQUFPTCxFQUFNTSxPQUNqQixLQUFPRCxHQUFNLENBQ1QsR0FBSUEsRUFBS25GLFNBQTRCLE1BQWpCbUYsRUFBS25GLFNBQW1CbUYsRUFBS0ssS0FBTSxDQUNuRCxHQUFJTCxFQUFLcEcsYUFBYSxRQUFRMEcsV0FBVyxLQUNyQyxPQUdKLEdBQUlGLEVBQXVCRyxLQUFLQyxHQUFVUixFQUFLSyxLQUFLQyxXQUFXRSxJQUMzRCxPQUVKLE1BQU1DLEVBQVdULEVBQUtwRyxhQUFhLGNBQWdCb0csRUFBS3BHLGFBQWEsUUFFckUsTUFBSyxjQUFjOEcsS0FBS0QsUUFNeEIsR0FMSXBDLEVBQVVvQixZQUFZLFdBQVksQ0FBRVksS0FBTUksSUFDMUNkLEVBQU1nQixzQkFDTmhCLEVBQU1pQixtQkFLZFosRUFBT0EsRUFBS0UsY0FFakIsR0FDSHZFLE9BQU8rRCxpQkFBaUIsU0FBVTlCLEVBQVMsS0FDdkMsR0FBSUMsRUFDQUEsR0FBaUIsTUFFaEIsQ0FDRCxNQUFNMUQsRUFBT3dELEVBQWNaLGlDQUFpQ3BCLE9BQU9DLFNBQy9DLGlCQUFUekIsR0FBc0JTLE1BQU1ULEtBQ25Da0UsRUFBVW9CLFlBQVksYUFBYyxDQUFFdEYsU0FDdENnRSxFQUFNaEUsS0FBT0EsRUFDYjhELEVBQU9HLFNBQVNELE1BR3pCLE0sNkJDckpIcEcsT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBS3RELE1BQU1xRixFQUFnQixFQUFRLEdBd0I5QnhHLEVBQVE0RyxpQkF2QlIsTUFDSSwrQkFBK0I1RCxHQUMzQixNQUFNLFNBQUVrQixHQUFhc0MsRUFBYzNDLHlCQUF5QmIsR0FDNUQwRyxLQUFLQyxRQUFRekYsR0FBWUEsRUFBUzdCLFNBRXRDLFFBQVF1SCxHQUNKRixLQUFLRyxxQkFBcUJILEtBQUtJLFVBQy9CSixLQUFLSyxtQkFBbUJILEdBQ3hCRixLQUFLSSxTQUFXRixFQUVwQixxQkFBcUJ2SCxHQUNaQSxJQUdMQSxFQUFRMkgsVUFBWTNILEVBQVEySCxVQUFVQyxRQUFRLHdCQUF5QixLQUUzRSxtQkFBbUI1SCxHQUNWQSxJQUdMQSxFQUFRMkgsV0FBYSx3Qiw2QkN0QjdCcEosT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBU3REbkIsRUFBUXlILG1CQVJSLFNBQTRCeUMsR0FDSSxZQUF4QjVILFNBQVM2SCxZQUFvRCxrQkFBeEI3SCxTQUFTNkgsV0FDOUM3SCxTQUFTaUcsaUJBQWlCLG1CQUFvQjJCLEdBRzlDQSxNLDZCQ05SdEosT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBQ3RELE1BQU0yQixFQUFhLEVBQVEsR0FDM0I5QyxFQUFRbUgsc0JBQXlCTCxHQUN0QixJQUFJLE1BQ1AsWUFBWTRCLEVBQU1uRixHQUNkdUQsRUFBT3dCLFlBQVksQ0FDZkksT0FDQUQsT0FBUTNGLEVBQVdELGNBQWM0RixPQUNqQ2xGLFksaUJDYmhCLFlBVUEsSUFBSTZHLEVBQWtCLHNCQUdsQkMsRUFBTSxJQUdOQyxFQUFZLGtCQUdaQyxFQUFTLGFBR1RDLEVBQWEscUJBR2JDLEVBQWEsYUFHYkMsRUFBWSxjQUdaQyxFQUFlQyxTQUdmQyxFQUE4QixpQkFBVkMsR0FBc0JBLEdBQVVBLEVBQU9sSyxTQUFXQSxRQUFVa0ssRUFHaEZDLEVBQTBCLGlCQUFSQyxNQUFvQkEsTUFBUUEsS0FBS3BLLFNBQVdBLFFBQVVvSyxLQUd4RUMsRUFBT0osR0FBY0UsR0FBWUcsU0FBUyxjQUFUQSxHQVVqQ0MsRUFQY3ZLLE9BQU9rQixVQU9Rc0osU0FHN0JDLEVBQVlqSSxLQUFLRixJQUNqQm9JLEVBQVlsSSxLQUFLSCxJQWtCakJzSSxFQUFNLFdBQ1IsT0FBT04sRUFBS08sS0FBS0QsT0F5RG5CLFNBQVNFLEVBQVNDLEVBQU1DLEVBQU1DLEdBQzVCLElBQUlDLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQ0FDLEVBQWlCLEVBQ2pCQyxHQUFVLEVBQ1ZDLEdBQVMsRUFDVEMsR0FBVyxFQUVmLEdBQW1CLG1CQUFSWixFQUNULE1BQU0sSUFBSWEsVUFBVW5DLEdBVXRCLFNBQVNvQyxFQUFXQyxHQUNsQixJQUFJQyxFQUFPYixFQUNQYyxFQUFVYixFQUtkLE9BSEFELEVBQVdDLE9BQVczSixFQUN0QmdLLEVBQWlCTSxFQUNqQlQsRUFBU04sRUFBS2tCLE1BQU1ELEVBQVNELEdBcUIvQixTQUFTRyxFQUFhSixHQUNwQixJQUFJSyxFQUFvQkwsRUFBT1AsRUFNL0IsWUFBeUIvSixJQUFqQitKLEdBQStCWSxHQUFxQm5CLEdBQ3pEbUIsRUFBb0IsR0FBT1QsR0FOSkksRUFBT04sR0FNOEJKLEVBR2pFLFNBQVNnQixJQUNQLElBQUlOLEVBQU9sQixJQUNYLEdBQUlzQixFQUFhSixHQUNmLE9BQU9PLEVBQWFQLEdBR3RCUixFQUFVdkUsV0FBV3FGLEVBekJ2QixTQUF1Qk4sR0FDckIsSUFFSVQsRUFBU0wsR0FGV2MsRUFBT1AsR0FJL0IsT0FBT0csRUFBU2YsRUFBVVUsRUFBUUQsR0FIUlUsRUFBT04sSUFHa0NILEVBb0JoQ2lCLENBQWNSLElBR25ELFNBQVNPLEVBQWFQLEdBS3BCLE9BSkFSLE9BQVU5SixFQUlObUssR0FBWVQsRUFDUFcsRUFBV0MsSUFFcEJaLEVBQVdDLE9BQVczSixFQUNmNkosR0FlVCxTQUFTa0IsSUFDUCxJQUFJVCxFQUFPbEIsSUFDUDRCLEVBQWFOLEVBQWFKLEdBTTlCLEdBSkFaLEVBQVd1QixVQUNYdEIsRUFBV3BDLEtBQ1h3QyxFQUFlTyxFQUVYVSxFQUFZLENBQ2QsUUFBZ0JoTCxJQUFaOEosRUFDRixPQXZFTixTQUFxQlEsR0FNbkIsT0FKQU4sRUFBaUJNLEVBRWpCUixFQUFVdkUsV0FBV3FGLEVBQWNwQixHQUU1QlMsRUFBVUksRUFBV0MsR0FBUVQsRUFpRXpCcUIsQ0FBWW5CLEdBRXJCLEdBQUlHLEVBR0YsT0FEQUosRUFBVXZFLFdBQVdxRixFQUFjcEIsR0FDNUJhLEVBQVdOLEdBTXRCLFlBSGdCL0osSUFBWjhKLElBQ0ZBLEVBQVV2RSxXQUFXcUYsRUFBY3BCLElBRTlCSyxFQUlULE9BeEdBTCxFQUFPMkIsRUFBUzNCLElBQVMsRUFDckI0QixFQUFTM0IsS0FDWFEsSUFBWVIsRUFBUVEsUUFFcEJMLEdBREFNLEVBQVMsWUFBYVQsR0FDSFAsRUFBVWlDLEVBQVMxQixFQUFRRyxVQUFZLEVBQUdKLEdBQVFJLEVBQ3JFTyxFQUFXLGFBQWNWLElBQVlBLEVBQVFVLFNBQVdBLEdBaUcxRFksRUFBVU0sT0FuQ1YsZ0JBQ2tCckwsSUFBWjhKLEdBQ0Z3QixhQUFheEIsR0FFZkUsRUFBaUIsRUFDakJOLEVBQVdLLEVBQWVKLEVBQVdHLE9BQVU5SixHQStCakQrSyxFQUFVUSxNQTVCVixXQUNFLFlBQW1CdkwsSUFBWjhKLEVBQXdCRCxFQUFTZ0IsRUFBYXpCLE1BNEJoRDJCLEVBMEZULFNBQVNLLEVBQVNwTSxHQUNoQixJQUFJdUgsU0FBY3ZILEVBQ2xCLFFBQVNBLElBQWtCLFVBQVJ1SCxHQUE0QixZQUFSQSxHQTRFekMsU0FBUzRFLEVBQVNuTSxHQUNoQixHQUFvQixpQkFBVEEsRUFDVCxPQUFPQSxFQUVULEdBaENGLFNBQWtCQSxHQUNoQixNQUF1QixpQkFBVEEsR0F0QmhCLFNBQXNCQSxHQUNwQixRQUFTQSxHQUF5QixpQkFBVEEsRUFzQnRCd00sQ0FBYXhNLElBQVVnSyxFQUFlOUssS0FBS2MsSUFBVW1KLEVBOEJwRHNELENBQVN6TSxHQUNYLE9BQU9rSixFQUVULEdBQUlrRCxFQUFTcE0sR0FBUSxDQUNuQixJQUFJME0sRUFBZ0MsbUJBQWpCMU0sRUFBTTJNLFFBQXdCM00sRUFBTTJNLFVBQVkzTSxFQUNuRUEsRUFBUW9NLEVBQVNNLEdBQVVBLEVBQVEsR0FBTUEsRUFFM0MsR0FBb0IsaUJBQVQxTSxFQUNULE9BQWlCLElBQVZBLEVBQWNBLEdBQVNBLEVBRWhDQSxFQUFRQSxFQUFNOEksUUFBUU0sRUFBUSxJQUM5QixJQUFJd0QsRUFBV3RELEVBQVdsQixLQUFLcEksR0FDL0IsT0FBUTRNLEdBQVlyRCxFQUFVbkIsS0FBS3BJLEdBQy9Cd0osRUFBYXhKLEVBQU02TSxNQUFNLEdBQUlELEVBQVcsRUFBSSxHQUMzQ3ZELEVBQVdqQixLQUFLcEksR0FBU2tKLEdBQU9sSixFQUd2Q2xCLEVBQU9ELFFBOUlQLFNBQWtCMEwsRUFBTUMsRUFBTUMsR0FDNUIsSUFBSVEsR0FBVSxFQUNWRSxHQUFXLEVBRWYsR0FBbUIsbUJBQVJaLEVBQ1QsTUFBTSxJQUFJYSxVQUFVbkMsR0FNdEIsT0FKSW1ELEVBQVMzQixLQUNYUSxFQUFVLFlBQWFSLElBQVlBLEVBQVFRLFFBQVVBLEVBQ3JERSxFQUFXLGFBQWNWLElBQVlBLEVBQVFVLFNBQVdBLEdBRW5EYixFQUFTQyxFQUFNQyxFQUFNLENBQzFCLFFBQVdTLEVBQ1gsUUFBV1QsRUFDWCxTQUFZVyxPLCtCQ3RUaEIsSUFBSTJCLEVBR0pBLEVBQUksV0FDSCxPQUFPdkUsS0FESixHQUlKLElBRUN1RSxFQUFJQSxHQUFLLElBQUkvQyxTQUFTLGNBQWIsR0FDUixNQUFPZ0QsR0FFYyxpQkFBWDFKLFNBQXFCeUosRUFBSXpKLFFBT3JDdkUsRUFBT0QsUUFBVWlPIiwiZmlsZSI6ImluZGV4LmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pIHtcbiBcdFx0XHRyZXR1cm4gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0uZXhwb3J0cztcbiBcdFx0fVxuIFx0XHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuIFx0XHR2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gXHRcdFx0aTogbW9kdWxlSWQsXG4gXHRcdFx0bDogZmFsc2UsXG4gXHRcdFx0ZXhwb3J0czoge31cbiBcdFx0fTtcblxuIFx0XHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cbiBcdFx0bW9kdWxlc1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cbiBcdFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxuIFx0XHRtb2R1bGUubCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbihleHBvcnRzLCBuYW1lLCBnZXR0ZXIpIHtcbiBcdFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZ2V0dGVyIH0pO1xuIFx0XHR9XG4gXHR9O1xuXG4gXHQvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSBmdW5jdGlvbihleHBvcnRzKSB7XG4gXHRcdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuIFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuIFx0XHR9XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG4gXHR9O1xuXG4gXHQvLyBjcmVhdGUgYSBmYWtlIG5hbWVzcGFjZSBvYmplY3RcbiBcdC8vIG1vZGUgJiAxOiB2YWx1ZSBpcyBhIG1vZHVsZSBpZCwgcmVxdWlyZSBpdFxuIFx0Ly8gbW9kZSAmIDI6IG1lcmdlIGFsbCBwcm9wZXJ0aWVzIG9mIHZhbHVlIGludG8gdGhlIG5zXG4gXHQvLyBtb2RlICYgNDogcmV0dXJuIHZhbHVlIHdoZW4gYWxyZWFkeSBucyBvYmplY3RcbiBcdC8vIG1vZGUgJiA4fDE6IGJlaGF2ZSBsaWtlIHJlcXVpcmVcbiBcdF9fd2VicGFja19yZXF1aXJlX18udCA9IGZ1bmN0aW9uKHZhbHVlLCBtb2RlKSB7XG4gXHRcdGlmKG1vZGUgJiAxKSB2YWx1ZSA9IF9fd2VicGFja19yZXF1aXJlX18odmFsdWUpO1xuIFx0XHRpZihtb2RlICYgOCkgcmV0dXJuIHZhbHVlO1xuIFx0XHRpZigobW9kZSAmIDQpICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgJiYgdmFsdWUuX19lc01vZHVsZSkgcmV0dXJuIHZhbHVlO1xuIFx0XHR2YXIgbnMgPSBPYmplY3QuY3JlYXRlKG51bGwpO1xuIFx0XHRfX3dlYnBhY2tfcmVxdWlyZV9fLnIobnMpO1xuIFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0JywgeyBlbnVtZXJhYmxlOiB0cnVlLCB2YWx1ZTogdmFsdWUgfSk7XG4gXHRcdGlmKG1vZGUgJiAyICYmIHR5cGVvZiB2YWx1ZSAhPSAnc3RyaW5nJykgZm9yKHZhciBrZXkgaW4gdmFsdWUpIF9fd2VicGFja19yZXF1aXJlX18uZChucywga2V5LCBmdW5jdGlvbihrZXkpIHsgcmV0dXJuIHZhbHVlW2tleV07IH0uYmluZChudWxsLCBrZXkpKTtcbiBcdFx0cmV0dXJuIG5zO1xuIFx0fTtcblxuIFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubiA9IGZ1bmN0aW9uKG1vZHVsZSkge1xuIFx0XHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cbiBcdFx0XHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxuIFx0XHRcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18uZChnZXR0ZXIsICdhJywgZ2V0dGVyKTtcbiBcdFx0cmV0dXJuIGdldHRlcjtcbiBcdH07XG5cbiBcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkgeyByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpOyB9O1xuXG4gXHQvLyBfX3dlYnBhY2tfcHVibGljX3BhdGhfX1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXCJcIjtcblxuXG4gXHQvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcbiBcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IDIpO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmxldCBjYWNoZWRTZXR0aW5ncyA9IHVuZGVmaW5lZDtcbmZ1bmN0aW9uIGdldERhdGEoa2V5KSB7XG4gICAgY29uc3QgZWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd2c2NvZGUtbWFya2Rvd24tcHJldmlldy1kYXRhJyk7XG4gICAgaWYgKGVsZW1lbnQpIHtcbiAgICAgICAgY29uc3QgZGF0YSA9IGVsZW1lbnQuZ2V0QXR0cmlidXRlKGtleSk7XG4gICAgICAgIGlmIChkYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShkYXRhKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBsb2FkIGRhdGEgZm9yICR7a2V5fWApO1xufVxuZXhwb3J0cy5nZXREYXRhID0gZ2V0RGF0YTtcbmZ1bmN0aW9uIGdldFNldHRpbmdzKCkge1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIGNhY2hlZFNldHRpbmdzID0gZ2V0RGF0YSgnZGF0YS1zZXR0aW5ncycpO1xuICAgIGlmIChjYWNoZWRTZXR0aW5ncykge1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0dGluZ3M7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGxvYWQgc2V0dGluZ3MnKTtcbn1cbmV4cG9ydHMuZ2V0U2V0dGluZ3MgPSBnZXRTZXR0aW5ncztcbiIsIlwidXNlIHN0cmljdFwiO1xuLyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAqICBDb3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqICBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIExpY2Vuc2UuIFNlZSBMaWNlbnNlLnR4dCBpbiB0aGUgcHJvamVjdCByb290IGZvciBsaWNlbnNlIGluZm9ybWF0aW9uLlxuICotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHsgdmFsdWU6IHRydWUgfSk7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5mdW5jdGlvbiBjbGFtcChtaW4sIG1heCwgdmFsdWUpIHtcbiAgICByZXR1cm4gTWF0aC5taW4obWF4LCBNYXRoLm1heChtaW4sIHZhbHVlKSk7XG59XG5mdW5jdGlvbiBjbGFtcExpbmUobGluZSkge1xuICAgIHJldHVybiBjbGFtcCgwLCBzZXR0aW5nc18xLmdldFNldHRpbmdzKCkubGluZUNvdW50IC0gMSwgbGluZSk7XG59XG5jb25zdCBnZXRDb2RlTGluZUVsZW1lbnRzID0gKCgpID0+IHtcbiAgICBsZXQgZWxlbWVudHM7XG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgICAgaWYgKCFlbGVtZW50cykge1xuICAgICAgICAgICAgZWxlbWVudHMgPSBbeyBlbGVtZW50OiBkb2N1bWVudC5ib2R5LCBsaW5lOiAwIH1dO1xuICAgICAgICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ2NvZGUtbGluZScpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgbGluZSA9ICtlbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS1saW5lJyk7XG4gICAgICAgICAgICAgICAgaWYgKGlzTmFOKGxpbmUpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudC50YWdOYW1lID09PSAnQ09ERScgJiYgZWxlbWVudC5wYXJlbnRFbGVtZW50ICYmIGVsZW1lbnQucGFyZW50RWxlbWVudC50YWdOYW1lID09PSAnUFJFJykge1xuICAgICAgICAgICAgICAgICAgICAvLyBGZW5jaGVkIGNvZGUgYmxvY2tzIGFyZSBhIHNwZWNpYWwgY2FzZSBzaW5jZSB0aGUgYGNvZGUtbGluZWAgY2FuIG9ubHkgYmUgbWFya2VkIG9uXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSBgPGNvZGU+YCBlbGVtZW50IGFuZCBub3QgdGhlIHBhcmVudCBgPHByZT5gIGVsZW1lbnQuXG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnRzLnB1c2goeyBlbGVtZW50OiBlbGVtZW50LnBhcmVudEVsZW1lbnQsIGxpbmUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBlbGVtZW50cy5wdXNoKHsgZWxlbWVudDogZWxlbWVudCwgbGluZSB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVsZW1lbnRzO1xuICAgIH07XG59KSgpO1xuLyoqXG4gKiBGaW5kIHRoZSBodG1sIGVsZW1lbnRzIHRoYXQgbWFwIHRvIGEgc3BlY2lmaWMgdGFyZ2V0IGxpbmUgaW4gdGhlIGVkaXRvci5cbiAqXG4gKiBJZiBhbiBleGFjdCBtYXRjaCwgcmV0dXJucyBhIHNpbmdsZSBlbGVtZW50LiBJZiB0aGUgbGluZSBpcyBiZXR3ZWVuIGVsZW1lbnRzLFxuICogcmV0dXJucyB0aGUgZWxlbWVudCBwcmlvciB0byBhbmQgdGhlIGVsZW1lbnQgYWZ0ZXIgdGhlIGdpdmVuIGxpbmUuXG4gKi9cbmZ1bmN0aW9uIGdldEVsZW1lbnRzRm9yU291cmNlTGluZSh0YXJnZXRMaW5lKSB7XG4gICAgY29uc3QgbGluZU51bWJlciA9IE1hdGguZmxvb3IodGFyZ2V0TGluZSk7XG4gICAgY29uc3QgbGluZXMgPSBnZXRDb2RlTGluZUVsZW1lbnRzKCk7XG4gICAgbGV0IHByZXZpb3VzID0gbGluZXNbMF0gfHwgbnVsbDtcbiAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIGxpbmVzKSB7XG4gICAgICAgIGlmIChlbnRyeS5saW5lID09PSBsaW5lTnVtYmVyKSB7XG4gICAgICAgICAgICByZXR1cm4geyBwcmV2aW91czogZW50cnksIG5leHQ6IHVuZGVmaW5lZCB9O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGVudHJ5LmxpbmUgPiBsaW5lTnVtYmVyKSB7XG4gICAgICAgICAgICByZXR1cm4geyBwcmV2aW91cywgbmV4dDogZW50cnkgfTtcbiAgICAgICAgfVxuICAgICAgICBwcmV2aW91cyA9IGVudHJ5O1xuICAgIH1cbiAgICByZXR1cm4geyBwcmV2aW91cyB9O1xufVxuZXhwb3J0cy5nZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUgPSBnZXRFbGVtZW50c0ZvclNvdXJjZUxpbmU7XG4vKipcbiAqIEZpbmQgdGhlIGh0bWwgZWxlbWVudHMgdGhhdCBhcmUgYXQgYSBzcGVjaWZpYyBwaXhlbCBvZmZzZXQgb24gdGhlIHBhZ2UuXG4gKi9cbmZ1bmN0aW9uIGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldChvZmZzZXQpIHtcbiAgICBjb25zdCBsaW5lcyA9IGdldENvZGVMaW5lRWxlbWVudHMoKTtcbiAgICBjb25zdCBwb3NpdGlvbiA9IG9mZnNldCAtIHdpbmRvdy5zY3JvbGxZO1xuICAgIGxldCBsbyA9IC0xO1xuICAgIGxldCBoaSA9IGxpbmVzLmxlbmd0aCAtIDE7XG4gICAgd2hpbGUgKGxvICsgMSA8IGhpKSB7XG4gICAgICAgIGNvbnN0IG1pZCA9IE1hdGguZmxvb3IoKGxvICsgaGkpIC8gMik7XG4gICAgICAgIGNvbnN0IGJvdW5kcyA9IGxpbmVzW21pZF0uZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgICAgaWYgKGJvdW5kcy50b3AgKyBib3VuZHMuaGVpZ2h0ID49IHBvc2l0aW9uKSB7XG4gICAgICAgICAgICBoaSA9IG1pZDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGxvID0gbWlkO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGhpRWxlbWVudCA9IGxpbmVzW2hpXTtcbiAgICBjb25zdCBoaUJvdW5kcyA9IGhpRWxlbWVudC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGlmIChoaSA+PSAxICYmIGhpQm91bmRzLnRvcCA+IHBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGxvRWxlbWVudCA9IGxpbmVzW2xvXTtcbiAgICAgICAgcmV0dXJuIHsgcHJldmlvdXM6IGxvRWxlbWVudCwgbmV4dDogaGlFbGVtZW50IH07XG4gICAgfVxuICAgIGlmIChoaSA+IDEgJiYgaGkgPCBsaW5lcy5sZW5ndGggJiYgaGlCb3VuZHMudG9wICsgaGlCb3VuZHMuaGVpZ2h0ID4gcG9zaXRpb24pIHtcbiAgICAgICAgcmV0dXJuIHsgcHJldmlvdXM6IGhpRWxlbWVudCwgbmV4dDogbGluZXNbaGkgKyAxXSB9O1xuICAgIH1cbiAgICByZXR1cm4geyBwcmV2aW91czogaGlFbGVtZW50IH07XG59XG5leHBvcnRzLmdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldCA9IGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldDtcbi8qKlxuICogQXR0ZW1wdCB0byByZXZlYWwgdGhlIGVsZW1lbnQgZm9yIGEgc291cmNlIGxpbmUgaW4gdGhlIGVkaXRvci5cbiAqL1xuZnVuY3Rpb24gc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGxpbmUpIHtcbiAgICBpZiAoIXNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChsaW5lIDw9IDApIHtcbiAgICAgICAgd2luZG93LnNjcm9sbCh3aW5kb3cuc2Nyb2xsWCwgMCk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgeyBwcmV2aW91cywgbmV4dCB9ID0gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lKGxpbmUpO1xuICAgIGlmICghcHJldmlvdXMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgc2Nyb2xsVG8gPSAwO1xuICAgIGNvbnN0IHJlY3QgPSBwcmV2aW91cy5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIGNvbnN0IHByZXZpb3VzVG9wID0gcmVjdC50b3A7XG4gICAgaWYgKG5leHQgJiYgbmV4dC5saW5lICE9PSBwcmV2aW91cy5saW5lKSB7XG4gICAgICAgIC8vIEJldHdlZW4gdHdvIGVsZW1lbnRzLiBHbyB0byBwZXJjZW50YWdlIG9mZnNldCBiZXR3ZWVuIHRoZW0uXG4gICAgICAgIGNvbnN0IGJldHdlZW5Qcm9ncmVzcyA9IChsaW5lIC0gcHJldmlvdXMubGluZSkgLyAobmV4dC5saW5lIC0gcHJldmlvdXMubGluZSk7XG4gICAgICAgIGNvbnN0IGVsZW1lbnRPZmZzZXQgPSBuZXh0LmVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkudG9wIC0gcHJldmlvdXNUb3A7XG4gICAgICAgIHNjcm9sbFRvID0gcHJldmlvdXNUb3AgKyBiZXR3ZWVuUHJvZ3Jlc3MgKiBlbGVtZW50T2Zmc2V0O1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgY29uc3QgcHJvZ3Jlc3NJbkVsZW1lbnQgPSBsaW5lIC0gTWF0aC5mbG9vcihsaW5lKTtcbiAgICAgICAgc2Nyb2xsVG8gPSBwcmV2aW91c1RvcCArIChyZWN0LmhlaWdodCAqIHByb2dyZXNzSW5FbGVtZW50KTtcbiAgICB9XG4gICAgd2luZG93LnNjcm9sbCh3aW5kb3cuc2Nyb2xsWCwgTWF0aC5tYXgoMSwgd2luZG93LnNjcm9sbFkgKyBzY3JvbGxUbykpO1xufVxuZXhwb3J0cy5zY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUgPSBzY3JvbGxUb1JldmVhbFNvdXJjZUxpbmU7XG5mdW5jdGlvbiBnZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldChvZmZzZXQpIHtcbiAgICBjb25zdCB7IHByZXZpb3VzLCBuZXh0IH0gPSBnZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQob2Zmc2V0KTtcbiAgICBpZiAocHJldmlvdXMpIHtcbiAgICAgICAgY29uc3QgcHJldmlvdXNCb3VuZHMgPSBwcmV2aW91cy5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCBvZmZzZXRGcm9tUHJldmlvdXMgPSAob2Zmc2V0IC0gd2luZG93LnNjcm9sbFkgLSBwcmV2aW91c0JvdW5kcy50b3ApO1xuICAgICAgICBpZiAobmV4dCkge1xuICAgICAgICAgICAgY29uc3QgcHJvZ3Jlc3NCZXR3ZWVuRWxlbWVudHMgPSBvZmZzZXRGcm9tUHJldmlvdXMgLyAobmV4dC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIHByZXZpb3VzQm91bmRzLnRvcCk7XG4gICAgICAgICAgICBjb25zdCBsaW5lID0gcHJldmlvdXMubGluZSArIHByb2dyZXNzQmV0d2VlbkVsZW1lbnRzICogKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuICAgICAgICAgICAgcmV0dXJuIGNsYW1wTGluZShsaW5lKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHByb2dyZXNzV2l0aGluRWxlbWVudCA9IG9mZnNldEZyb21QcmV2aW91cyAvIChwcmV2aW91c0JvdW5kcy5oZWlnaHQpO1xuICAgICAgICAgICAgY29uc3QgbGluZSA9IHByZXZpb3VzLmxpbmUgKyBwcm9ncmVzc1dpdGhpbkVsZW1lbnQ7XG4gICAgICAgICAgICByZXR1cm4gY2xhbXBMaW5lKGxpbmUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuZXhwb3J0cy5nZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCA9IGdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0O1xuLyoqXG4gKiBUcnkgdG8gZmluZCB0aGUgaHRtbCBlbGVtZW50IGJ5IHVzaW5nIGEgZnJhZ21lbnQgaWRcbiAqL1xuZnVuY3Rpb24gZ2V0TGluZUVsZW1lbnRGb3JGcmFnbWVudChmcmFnbWVudCkge1xuICAgIHJldHVybiBnZXRDb2RlTGluZUVsZW1lbnRzKCkuZmluZCgoZWxlbWVudCkgPT4ge1xuICAgICAgICByZXR1cm4gZWxlbWVudC5lbGVtZW50LmlkID09PSBmcmFnbWVudDtcbiAgICB9KTtcbn1cbmV4cG9ydHMuZ2V0TGluZUVsZW1lbnRGb3JGcmFnbWVudCA9IGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgYWN0aXZlTGluZU1hcmtlcl8xID0gcmVxdWlyZShcIi4vYWN0aXZlTGluZU1hcmtlclwiKTtcbmNvbnN0IGV2ZW50c18xID0gcmVxdWlyZShcIi4vZXZlbnRzXCIpO1xuY29uc3QgbWVzc2FnaW5nXzEgPSByZXF1aXJlKFwiLi9tZXNzYWdpbmdcIik7XG5jb25zdCBzY3JvbGxfc3luY18xID0gcmVxdWlyZShcIi4vc2Nyb2xsLXN5bmNcIik7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5jb25zdCB0aHJvdHRsZSA9IHJlcXVpcmUoXCJsb2Rhc2gudGhyb3R0bGVcIik7XG5sZXQgc2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuY29uc3QgbWFya2VyID0gbmV3IGFjdGl2ZUxpbmVNYXJrZXJfMS5BY3RpdmVMaW5lTWFya2VyKCk7XG5jb25zdCBzZXR0aW5ncyA9IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKTtcbmNvbnN0IHZzY29kZSA9IGFjcXVpcmVWc0NvZGVBcGkoKTtcbi8vIFNldCBWUyBDb2RlIHN0YXRlXG5sZXQgc3RhdGUgPSBzZXR0aW5nc18xLmdldERhdGEoJ2RhdGEtc3RhdGUnKTtcbnZzY29kZS5zZXRTdGF0ZShzdGF0ZSk7XG5jb25zdCBtZXNzYWdpbmcgPSBtZXNzYWdpbmdfMS5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUodnNjb2RlKTtcbndpbmRvdy5jc3BBbGVydGVyLnNldFBvc3RlcihtZXNzYWdpbmcpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3Iuc2V0UG9zdGVyKG1lc3NhZ2luZyk7XG53aW5kb3cub25sb2FkID0gKCkgPT4ge1xuICAgIHVwZGF0ZUltYWdlU2l6ZXMoKTtcbn07XG5ldmVudHNfMS5vbmNlRG9jdW1lbnRMb2FkZWQoKCkgPT4ge1xuICAgIGlmIChzZXR0aW5ncy5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIC8vIFRyeSB0byBzY3JvbGwgdG8gZnJhZ21lbnQgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBpZiAoc3RhdGUuZnJhZ21lbnQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gc2Nyb2xsX3N5bmNfMS5nZXRMaW5lRWxlbWVudEZvckZyYWdtZW50KHN0YXRlLmZyYWdtZW50KTtcbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGVsZW1lbnQubGluZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5pdGlhbExpbmUgPSArc2V0dGluZ3MubGluZTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGluaXRpYWxMaW5lKSkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGluaXRpYWxMaW5lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDApO1xuICAgIH1cbn0pO1xuY29uc3Qgb25VcGRhdGVWaWV3ID0gKCgpID0+IHtcbiAgICBjb25zdCBkb1Njcm9sbCA9IHRocm90dGxlKChsaW5lKSA9PiB7XG4gICAgICAgIHNjcm9sbERpc2FibGVkID0gdHJ1ZTtcbiAgICAgICAgc2Nyb2xsX3N5bmNfMS5zY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUobGluZSk7XG4gICAgfSwgNTApO1xuICAgIHJldHVybiAobGluZSwgc2V0dGluZ3MpID0+IHtcbiAgICAgICAgaWYgKCFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgc2V0dGluZ3MubGluZSA9IGxpbmU7XG4gICAgICAgICAgICBkb1Njcm9sbChsaW5lKTtcbiAgICAgICAgfVxuICAgIH07XG59KSgpO1xubGV0IHVwZGF0ZUltYWdlU2l6ZXMgPSB0aHJvdHRsZSgoKSA9PiB7XG4gICAgY29uc3QgaW1hZ2VJbmZvID0gW107XG4gICAgbGV0IGltYWdlcyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbWcnKTtcbiAgICBpZiAoaW1hZ2VzKSB7XG4gICAgICAgIGxldCBpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgaW1hZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBpbWcgPSBpbWFnZXNbaV07XG4gICAgICAgICAgICBpZiAoaW1nLmNsYXNzTGlzdC5jb250YWlucygnbG9hZGluZycpKSB7XG4gICAgICAgICAgICAgICAgaW1nLmNsYXNzTGlzdC5yZW1vdmUoJ2xvYWRpbmcnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGltYWdlSW5mby5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogaW1nLmlkLFxuICAgICAgICAgICAgICAgIGhlaWdodDogaW1nLmhlaWdodCxcbiAgICAgICAgICAgICAgICB3aWR0aDogaW1nLndpZHRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NhY2hlSW1hZ2VTaXplcycsIGltYWdlSW5mbyk7XG4gICAgfVxufSwgNTApO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgdXBkYXRlSW1hZ2VTaXplcygpO1xufSwgdHJ1ZSk7XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGV2ZW50ID0+IHtcbiAgICBpZiAoZXZlbnQuZGF0YS5zb3VyY2UgIT09IHNldHRpbmdzLnNvdXJjZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHN3aXRjaCAoZXZlbnQuZGF0YS50eXBlKSB7XG4gICAgICAgIGNhc2UgJ29uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbic6XG4gICAgICAgICAgICBtYXJrZXIub25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGV2ZW50LmRhdGEubGluZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndXBkYXRlVmlldyc6XG4gICAgICAgICAgICBvblVwZGF0ZVZpZXcoZXZlbnQuZGF0YS5saW5lLCBzZXR0aW5ncyk7XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG59LCBmYWxzZSk7XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIGV2ZW50ID0+IHtcbiAgICBpZiAoIXNldHRpbmdzLmRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIElnbm9yZSBjbGlja3Mgb24gbGlua3NcbiAgICBmb3IgKGxldCBub2RlID0gZXZlbnQudGFyZ2V0OyBub2RlOyBub2RlID0gbm9kZS5wYXJlbnROb2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgPT09ICdBJykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IG9mZnNldCA9IGV2ZW50LnBhZ2VZO1xuICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgbWVzc2FnaW5nLnBvc3RNZXNzYWdlKCdkaWRDbGljaycsIHsgbGluZTogTWF0aC5mbG9vcihsaW5lKSB9KTtcbiAgICB9XG59KTtcbmNvbnN0IHBhc3NUaHJvdWdoTGlua1NjaGVtZXMgPSBbJ2h0dHA6JywgJ2h0dHBzOicsICdtYWlsdG86JywgJ3ZzY29kZTonLCAndnNjb2RlLWluc2lkZXJzOiddO1xuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBldmVudCA9PiB7XG4gICAgaWYgKCFldmVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBub2RlID0gZXZlbnQudGFyZ2V0O1xuICAgIHdoaWxlIChub2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgJiYgbm9kZS50YWdOYW1lID09PSAnQScgJiYgbm9kZS5ocmVmKSB7XG4gICAgICAgICAgICBpZiAobm9kZS5nZXRBdHRyaWJ1dGUoJ2hyZWYnKS5zdGFydHNXaXRoKCcjJykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBQYXNzIHRocm91Z2gga25vd24gc2NoZW1lc1xuICAgICAgICAgICAgaWYgKHBhc3NUaHJvdWdoTGlua1NjaGVtZXMuc29tZShzY2hlbWUgPT4gbm9kZS5ocmVmLnN0YXJ0c1dpdGgoc2NoZW1lKSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBocmVmVGV4dCA9IG5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLWhyZWYnKSB8fCBub2RlLmdldEF0dHJpYnV0ZSgnaHJlZicpO1xuICAgICAgICAgICAgLy8gSWYgb3JpZ2luYWwgbGluayBkb2Vzbid0IGxvb2sgbGlrZSBhIHVybCwgZGVsZWdhdGUgYmFjayB0byBWUyBDb2RlIHRvIHJlc29sdmVcbiAgICAgICAgICAgIGlmICghL15bYS16XFwtXSs6L2kudGVzdChocmVmVGV4dCkpIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ29wZW5MaW5rJywgeyBocmVmOiBocmVmVGV4dCB9KTtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgIH1cbn0sIHRydWUpO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRocm90dGxlKCgpID0+IHtcbiAgICBpZiAoc2Nyb2xsRGlzYWJsZWQpIHtcbiAgICAgICAgc2Nyb2xsRGlzYWJsZWQgPSBmYWxzZTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KHdpbmRvdy5zY3JvbGxZKTtcbiAgICAgICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgICAgIG1lc3NhZ2luZy5wb3N0TWVzc2FnZSgncmV2ZWFsTGluZScsIHsgbGluZSB9KTtcbiAgICAgICAgICAgIHN0YXRlLmxpbmUgPSBsaW5lO1xuICAgICAgICAgICAgdnNjb2RlLnNldFN0YXRlKHN0YXRlKTtcbiAgICAgICAgfVxuICAgIH1cbn0sIDUwKSk7XG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuY29uc3Qgc2Nyb2xsX3N5bmNfMSA9IHJlcXVpcmUoXCIuL3Njcm9sbC1zeW5jXCIpO1xuY2xhc3MgQWN0aXZlTGluZU1hcmtlciB7XG4gICAgb25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGxpbmUpIHtcbiAgICAgICAgY29uc3QgeyBwcmV2aW91cyB9ID0gc2Nyb2xsX3N5bmNfMS5nZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUobGluZSk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZShwcmV2aW91cyAmJiBwcmV2aW91cy5lbGVtZW50KTtcbiAgICB9XG4gICAgX3VwZGF0ZShiZWZvcmUpIHtcbiAgICAgICAgdGhpcy5fdW5tYXJrQWN0aXZlRWxlbWVudCh0aGlzLl9jdXJyZW50KTtcbiAgICAgICAgdGhpcy5fbWFya0FjdGl2ZUVsZW1lbnQoYmVmb3JlKTtcbiAgICAgICAgdGhpcy5fY3VycmVudCA9IGJlZm9yZTtcbiAgICB9XG4gICAgX3VubWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSA9IGVsZW1lbnQuY2xhc3NOYW1lLnJlcGxhY2UoL1xcYmNvZGUtYWN0aXZlLWxpbmVcXGIvZywgJycpO1xuICAgIH1cbiAgICBfbWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSArPSAnIGNvZGUtYWN0aXZlLWxpbmUnO1xuICAgIH1cbn1cbmV4cG9ydHMuQWN0aXZlTGluZU1hcmtlciA9IEFjdGl2ZUxpbmVNYXJrZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gb25jZURvY3VtZW50TG9hZGVkKGYpIHtcbiAgICBpZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnIHx8IGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICd1bmluaXRpYWxpemVkJykge1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBmKCk7XG4gICAgfVxufVxuZXhwb3J0cy5vbmNlRG9jdW1lbnRMb2FkZWQgPSBvbmNlRG9jdW1lbnRMb2FkZWQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3Qgc2V0dGluZ3NfMSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzXCIpO1xuZXhwb3J0cy5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUgPSAodnNjb2RlKSA9PiB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyB7XG4gICAgICAgIHBvc3RNZXNzYWdlKHR5cGUsIGJvZHkpIHtcbiAgICAgICAgICAgIHZzY29kZS5wb3N0TWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgdHlwZSxcbiAgICAgICAgICAgICAgICBzb3VyY2U6IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5zb3VyY2UsXG4gICAgICAgICAgICAgICAgYm9keVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9O1xufTtcbiIsIi8qKlxuICogbG9kYXNoIChDdXN0b20gQnVpbGQpIDxodHRwczovL2xvZGFzaC5jb20vPlxuICogQnVpbGQ6IGBsb2Rhc2ggbW9kdWxhcml6ZSBleHBvcnRzPVwibnBtXCIgLW8gLi9gXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9ycyA8aHR0cHM6Ly9qcXVlcnkub3JnLz5cbiAqIFJlbGVhc2VkIHVuZGVyIE1JVCBsaWNlbnNlIDxodHRwczovL2xvZGFzaC5jb20vbGljZW5zZT5cbiAqIEJhc2VkIG9uIFVuZGVyc2NvcmUuanMgMS44LjMgPGh0dHA6Ly91bmRlcnNjb3JlanMub3JnL0xJQ0VOU0U+XG4gKiBDb3B5cmlnaHQgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbiAqL1xuXG4vKiogVXNlZCBhcyB0aGUgYFR5cGVFcnJvcmAgbWVzc2FnZSBmb3IgXCJGdW5jdGlvbnNcIiBtZXRob2RzLiAqL1xudmFyIEZVTkNfRVJST1JfVEVYVCA9ICdFeHBlY3RlZCBhIGZ1bmN0aW9uJztcblxuLyoqIFVzZWQgYXMgcmVmZXJlbmNlcyBmb3IgdmFyaW91cyBgTnVtYmVyYCBjb25zdGFudHMuICovXG52YXIgTkFOID0gMCAvIDA7XG5cbi8qKiBgT2JqZWN0I3RvU3RyaW5nYCByZXN1bHQgcmVmZXJlbmNlcy4gKi9cbnZhciBzeW1ib2xUYWcgPSAnW29iamVjdCBTeW1ib2xdJztcblxuLyoqIFVzZWQgdG8gbWF0Y2ggbGVhZGluZyBhbmQgdHJhaWxpbmcgd2hpdGVzcGFjZS4gKi9cbnZhciByZVRyaW0gPSAvXlxccyt8XFxzKyQvZztcblxuLyoqIFVzZWQgdG8gZGV0ZWN0IGJhZCBzaWduZWQgaGV4YWRlY2ltYWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmFkSGV4ID0gL15bLStdMHhbMC05YS1mXSskL2k7XG5cbi8qKiBVc2VkIHRvIGRldGVjdCBiaW5hcnkgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmluYXJ5ID0gL14wYlswMV0rJC9pO1xuXG4vKiogVXNlZCB0byBkZXRlY3Qgb2N0YWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzT2N0YWwgPSAvXjBvWzAtN10rJC9pO1xuXG4vKiogQnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMgd2l0aG91dCBhIGRlcGVuZGVuY3kgb24gYHJvb3RgLiAqL1xudmFyIGZyZWVQYXJzZUludCA9IHBhcnNlSW50O1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYGdsb2JhbGAgZnJvbSBOb2RlLmpzLiAqL1xudmFyIGZyZWVHbG9iYWwgPSB0eXBlb2YgZ2xvYmFsID09ICdvYmplY3QnICYmIGdsb2JhbCAmJiBnbG9iYWwuT2JqZWN0ID09PSBPYmplY3QgJiYgZ2xvYmFsO1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYHNlbGZgLiAqL1xudmFyIGZyZWVTZWxmID0gdHlwZW9mIHNlbGYgPT0gJ29iamVjdCcgJiYgc2VsZiAmJiBzZWxmLk9iamVjdCA9PT0gT2JqZWN0ICYmIHNlbGY7XG5cbi8qKiBVc2VkIGFzIGEgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb2JqZWN0LiAqL1xudmFyIHJvb3QgPSBmcmVlR2xvYmFsIHx8IGZyZWVTZWxmIHx8IEZ1bmN0aW9uKCdyZXR1cm4gdGhpcycpKCk7XG5cbi8qKiBVc2VkIGZvciBidWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcy4gKi9cbnZhciBvYmplY3RQcm90byA9IE9iamVjdC5wcm90b3R5cGU7XG5cbi8qKlxuICogVXNlZCB0byByZXNvbHZlIHRoZVxuICogW2B0b1N0cmluZ1RhZ2BdKGh0dHA6Ly9lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLW9iamVjdC5wcm90b3R5cGUudG9zdHJpbmcpXG4gKiBvZiB2YWx1ZXMuXG4gKi9cbnZhciBvYmplY3RUb1N0cmluZyA9IG9iamVjdFByb3RvLnRvU3RyaW5nO1xuXG4vKiBCdWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcyBmb3IgdGhvc2Ugd2l0aCB0aGUgc2FtZSBuYW1lIGFzIG90aGVyIGBsb2Rhc2hgIG1ldGhvZHMuICovXG52YXIgbmF0aXZlTWF4ID0gTWF0aC5tYXgsXG4gICAgbmF0aXZlTWluID0gTWF0aC5taW47XG5cbi8qKlxuICogR2V0cyB0aGUgdGltZXN0YW1wIG9mIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRoYXQgaGF2ZSBlbGFwc2VkIHNpbmNlXG4gKiB0aGUgVW5peCBlcG9jaCAoMSBKYW51YXJ5IDE5NzAgMDA6MDA6MDAgVVRDKS5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDIuNC4wXG4gKiBAY2F0ZWdvcnkgRGF0ZVxuICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgdGltZXN0YW1wLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmRlZmVyKGZ1bmN0aW9uKHN0YW1wKSB7XG4gKiAgIGNvbnNvbGUubG9nKF8ubm93KCkgLSBzdGFtcCk7XG4gKiB9LCBfLm5vdygpKTtcbiAqIC8vID0+IExvZ3MgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgaXQgdG9vayBmb3IgdGhlIGRlZmVycmVkIGludm9jYXRpb24uXG4gKi9cbnZhciBub3cgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHJvb3QuRGF0ZS5ub3coKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlYm91bmNlZCBmdW5jdGlvbiB0aGF0IGRlbGF5cyBpbnZva2luZyBgZnVuY2AgdW50aWwgYWZ0ZXIgYHdhaXRgXG4gKiBtaWxsaXNlY29uZHMgaGF2ZSBlbGFwc2VkIHNpbmNlIHRoZSBsYXN0IHRpbWUgdGhlIGRlYm91bmNlZCBmdW5jdGlvbiB3YXNcbiAqIGludm9rZWQuIFRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgIG1ldGhvZCB0byBjYW5jZWxcbiAqIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLlxuICogUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2Agc2hvdWxkIGJlIGludm9rZWQgb24gdGhlXG4gKiBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGAgdGltZW91dC4gVGhlIGBmdW5jYCBpcyBpbnZva2VkXG4gKiB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50XG4gKiBjYWxscyB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYFxuICogaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIGRlYm91bmNlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy5kZWJvdW5jZWAgYW5kIGBfLnRocm90dGxlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlYm91bmNlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIGRlbGF5LlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9ZmFsc2VdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgbGVhZGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLm1heFdhaXRdXG4gKiAgVGhlIG1heGltdW0gdGltZSBgZnVuY2AgaXMgYWxsb3dlZCB0byBiZSBkZWxheWVkIGJlZm9yZSBpdCdzIGludm9rZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGRlYm91bmNlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgY29zdGx5IGNhbGN1bGF0aW9ucyB3aGlsZSB0aGUgd2luZG93IHNpemUgaXMgaW4gZmx1eC5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdyZXNpemUnLCBfLmRlYm91bmNlKGNhbGN1bGF0ZUxheW91dCwgMTUwKSk7XG4gKlxuICogLy8gSW52b2tlIGBzZW5kTWFpbGAgd2hlbiBjbGlja2VkLCBkZWJvdW5jaW5nIHN1YnNlcXVlbnQgY2FsbHMuXG4gKiBqUXVlcnkoZWxlbWVudCkub24oJ2NsaWNrJywgXy5kZWJvdW5jZShzZW5kTWFpbCwgMzAwLCB7XG4gKiAgICdsZWFkaW5nJzogdHJ1ZSxcbiAqICAgJ3RyYWlsaW5nJzogZmFsc2VcbiAqIH0pKTtcbiAqXG4gKiAvLyBFbnN1cmUgYGJhdGNoTG9nYCBpcyBpbnZva2VkIG9uY2UgYWZ0ZXIgMSBzZWNvbmQgb2YgZGVib3VuY2VkIGNhbGxzLlxuICogdmFyIGRlYm91bmNlZCA9IF8uZGVib3VuY2UoYmF0Y2hMb2csIDI1MCwgeyAnbWF4V2FpdCc6IDEwMDAgfSk7XG4gKiB2YXIgc291cmNlID0gbmV3IEV2ZW50U291cmNlKCcvc3RyZWFtJyk7XG4gKiBqUXVlcnkoc291cmNlKS5vbignbWVzc2FnZScsIGRlYm91bmNlZCk7XG4gKlxuICogLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyBkZWJvdW5jZWQgaW52b2NhdGlvbi5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIGRlYm91bmNlZC5jYW5jZWwpO1xuICovXG5mdW5jdGlvbiBkZWJvdW5jZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIHZhciBsYXN0QXJncyxcbiAgICAgIGxhc3RUaGlzLFxuICAgICAgbWF4V2FpdCxcbiAgICAgIHJlc3VsdCxcbiAgICAgIHRpbWVySWQsXG4gICAgICBsYXN0Q2FsbFRpbWUsXG4gICAgICBsYXN0SW52b2tlVGltZSA9IDAsXG4gICAgICBsZWFkaW5nID0gZmFsc2UsXG4gICAgICBtYXhpbmcgPSBmYWxzZSxcbiAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoRlVOQ19FUlJPUl9URVhUKTtcbiAgfVxuICB3YWl0ID0gdG9OdW1iZXIod2FpdCkgfHwgMDtcbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICEhb3B0aW9ucy5sZWFkaW5nO1xuICAgIG1heGluZyA9ICdtYXhXYWl0JyBpbiBvcHRpb25zO1xuICAgIG1heFdhaXQgPSBtYXhpbmcgPyBuYXRpdmVNYXgodG9OdW1iZXIob3B0aW9ucy5tYXhXYWl0KSB8fCAwLCB3YWl0KSA6IG1heFdhaXQ7XG4gICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgfVxuXG4gIGZ1bmN0aW9uIGludm9rZUZ1bmModGltZSkge1xuICAgIHZhciBhcmdzID0gbGFzdEFyZ3MsXG4gICAgICAgIHRoaXNBcmcgPSBsYXN0VGhpcztcblxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkodGhpc0FyZywgYXJncyk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGxlYWRpbmdFZGdlKHRpbWUpIHtcbiAgICAvLyBSZXNldCBhbnkgYG1heFdhaXRgIHRpbWVyLlxuICAgIGxhc3RJbnZva2VUaW1lID0gdGltZTtcbiAgICAvLyBTdGFydCB0aGUgdGltZXIgZm9yIHRoZSB0cmFpbGluZyBlZGdlLlxuICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgLy8gSW52b2tlIHRoZSBsZWFkaW5nIGVkZ2UuXG4gICAgcmV0dXJuIGxlYWRpbmcgPyBpbnZva2VGdW5jKHRpbWUpIDogcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gcmVtYWluaW5nV2FpdCh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZSxcbiAgICAgICAgcmVzdWx0ID0gd2FpdCAtIHRpbWVTaW5jZUxhc3RDYWxsO1xuXG4gICAgcmV0dXJuIG1heGluZyA/IG5hdGl2ZU1pbihyZXN1bHQsIG1heFdhaXQgLSB0aW1lU2luY2VMYXN0SW52b2tlKSA6IHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNob3VsZEludm9rZSh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZTtcblxuICAgIC8vIEVpdGhlciB0aGlzIGlzIHRoZSBmaXJzdCBjYWxsLCBhY3Rpdml0eSBoYXMgc3RvcHBlZCBhbmQgd2UncmUgYXQgdGhlXG4gICAgLy8gdHJhaWxpbmcgZWRnZSwgdGhlIHN5c3RlbSB0aW1lIGhhcyBnb25lIGJhY2t3YXJkcyBhbmQgd2UncmUgdHJlYXRpbmdcbiAgICAvLyBpdCBhcyB0aGUgdHJhaWxpbmcgZWRnZSwgb3Igd2UndmUgaGl0IHRoZSBgbWF4V2FpdGAgbGltaXQuXG4gICAgcmV0dXJuIChsYXN0Q2FsbFRpbWUgPT09IHVuZGVmaW5lZCB8fCAodGltZVNpbmNlTGFzdENhbGwgPj0gd2FpdCkgfHxcbiAgICAgICh0aW1lU2luY2VMYXN0Q2FsbCA8IDApIHx8IChtYXhpbmcgJiYgdGltZVNpbmNlTGFzdEludm9rZSA+PSBtYXhXYWl0KSk7XG4gIH1cblxuICBmdW5jdGlvbiB0aW1lckV4cGlyZWQoKSB7XG4gICAgdmFyIHRpbWUgPSBub3coKTtcbiAgICBpZiAoc2hvdWxkSW52b2tlKHRpbWUpKSB7XG4gICAgICByZXR1cm4gdHJhaWxpbmdFZGdlKHRpbWUpO1xuICAgIH1cbiAgICAvLyBSZXN0YXJ0IHRoZSB0aW1lci5cbiAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHJlbWFpbmluZ1dhaXQodGltZSkpO1xuICB9XG5cbiAgZnVuY3Rpb24gdHJhaWxpbmdFZGdlKHRpbWUpIHtcbiAgICB0aW1lcklkID0gdW5kZWZpbmVkO1xuXG4gICAgLy8gT25seSBpbnZva2UgaWYgd2UgaGF2ZSBgbGFzdEFyZ3NgIHdoaWNoIG1lYW5zIGBmdW5jYCBoYXMgYmVlblxuICAgIC8vIGRlYm91bmNlZCBhdCBsZWFzdCBvbmNlLlxuICAgIGlmICh0cmFpbGluZyAmJiBsYXN0QXJncykge1xuICAgICAgcmV0dXJuIGludm9rZUZ1bmModGltZSk7XG4gICAgfVxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNhbmNlbCgpIHtcbiAgICBpZiAodGltZXJJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXJJZCk7XG4gICAgfVxuICAgIGxhc3RJbnZva2VUaW1lID0gMDtcbiAgICBsYXN0QXJncyA9IGxhc3RDYWxsVGltZSA9IGxhc3RUaGlzID0gdGltZXJJZCA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGZsdXNoKCkge1xuICAgIHJldHVybiB0aW1lcklkID09PSB1bmRlZmluZWQgPyByZXN1bHQgOiB0cmFpbGluZ0VkZ2Uobm93KCkpO1xuICB9XG5cbiAgZnVuY3Rpb24gZGVib3VuY2VkKCkge1xuICAgIHZhciB0aW1lID0gbm93KCksXG4gICAgICAgIGlzSW52b2tpbmcgPSBzaG91bGRJbnZva2UodGltZSk7XG5cbiAgICBsYXN0QXJncyA9IGFyZ3VtZW50cztcbiAgICBsYXN0VGhpcyA9IHRoaXM7XG4gICAgbGFzdENhbGxUaW1lID0gdGltZTtcblxuICAgIGlmIChpc0ludm9raW5nKSB7XG4gICAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBsZWFkaW5nRWRnZShsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgICAgaWYgKG1heGluZykge1xuICAgICAgICAvLyBIYW5kbGUgaW52b2NhdGlvbnMgaW4gYSB0aWdodCBsb29wLlxuICAgICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgICAgICByZXR1cm4gaW52b2tlRnVuYyhsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIGRlYm91bmNlZC5jYW5jZWwgPSBjYW5jZWw7XG4gIGRlYm91bmNlZC5mbHVzaCA9IGZsdXNoO1xuICByZXR1cm4gZGVib3VuY2VkO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSB0aHJvdHRsZWQgZnVuY3Rpb24gdGhhdCBvbmx5IGludm9rZXMgYGZ1bmNgIGF0IG1vc3Qgb25jZSBwZXJcbiAqIGV2ZXJ5IGB3YWl0YCBtaWxsaXNlY29uZHMuIFRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgXG4gKiBtZXRob2QgdG8gY2FuY2VsIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvXG4gKiBpbW1lZGlhdGVseSBpbnZva2UgdGhlbS4gUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2BcbiAqIHNob3VsZCBiZSBpbnZva2VkIG9uIHRoZSBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGBcbiAqIHRpbWVvdXQuIFRoZSBgZnVuY2AgaXMgaW52b2tlZCB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGVcbiAqIHRocm90dGxlZCBmdW5jdGlvbi4gU3Vic2VxdWVudCBjYWxscyB0byB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uIHJldHVybiB0aGVcbiAqIHJlc3VsdCBvZiB0aGUgbGFzdCBgZnVuY2AgaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIHRocm90dGxlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy50aHJvdHRsZWAgYW5kIGBfLmRlYm91bmNlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHRocm90dGxlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHRocm90dGxlIGludm9jYXRpb25zIHRvLlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHRocm90dGxlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgZXhjZXNzaXZlbHkgdXBkYXRpbmcgdGhlIHBvc2l0aW9uIHdoaWxlIHNjcm9sbGluZy5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdzY3JvbGwnLCBfLnRocm90dGxlKHVwZGF0ZVBvc2l0aW9uLCAxMDApKTtcbiAqXG4gKiAvLyBJbnZva2UgYHJlbmV3VG9rZW5gIHdoZW4gdGhlIGNsaWNrIGV2ZW50IGlzIGZpcmVkLCBidXQgbm90IG1vcmUgdGhhbiBvbmNlIGV2ZXJ5IDUgbWludXRlcy5cbiAqIHZhciB0aHJvdHRsZWQgPSBfLnRocm90dGxlKHJlbmV3VG9rZW4sIDMwMDAwMCwgeyAndHJhaWxpbmcnOiBmYWxzZSB9KTtcbiAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCB0aHJvdHRsZWQpO1xuICpcbiAqIC8vIENhbmNlbCB0aGUgdHJhaWxpbmcgdGhyb3R0bGVkIGludm9jYXRpb24uXG4gKiBqUXVlcnkod2luZG93KS5vbigncG9wc3RhdGUnLCB0aHJvdHRsZWQuY2FuY2VsKTtcbiAqL1xuZnVuY3Rpb24gdGhyb3R0bGUoZnVuYywgd2FpdCwgb3B0aW9ucykge1xuICB2YXIgbGVhZGluZyA9IHRydWUsXG4gICAgICB0cmFpbGluZyA9IHRydWU7XG5cbiAgaWYgKHR5cGVvZiBmdW5jICE9ICdmdW5jdGlvbicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEZVTkNfRVJST1JfVEVYVCk7XG4gIH1cbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICdsZWFkaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLmxlYWRpbmcgOiBsZWFkaW5nO1xuICAgIHRyYWlsaW5nID0gJ3RyYWlsaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLnRyYWlsaW5nIDogdHJhaWxpbmc7XG4gIH1cbiAgcmV0dXJuIGRlYm91bmNlKGZ1bmMsIHdhaXQsIHtcbiAgICAnbGVhZGluZyc6IGxlYWRpbmcsXG4gICAgJ21heFdhaXQnOiB3YWl0LFxuICAgICd0cmFpbGluZyc6IHRyYWlsaW5nXG4gIH0pO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIHRoZVxuICogW2xhbmd1YWdlIHR5cGVdKGh0dHA6Ly93d3cuZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi83LjAvI3NlYy1lY21hc2NyaXB0LWxhbmd1YWdlLXR5cGVzKVxuICogb2YgYE9iamVjdGAuIChlLmcuIGFycmF5cywgZnVuY3Rpb25zLCBvYmplY3RzLCByZWdleGVzLCBgbmV3IE51bWJlcigwKWAsIGFuZCBgbmV3IFN0cmluZygnJylgKVxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIGFuIG9iamVjdCwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0KHt9KTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0KFsxLCAyLCAzXSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdChfLm5vb3ApO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3QobnVsbCk7XG4gKiAvLyA9PiBmYWxzZVxuICovXG5mdW5jdGlvbiBpc09iamVjdCh2YWx1ZSkge1xuICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgcmV0dXJuICEhdmFsdWUgJiYgKHR5cGUgPT0gJ29iamVjdCcgfHwgdHlwZSA9PSAnZnVuY3Rpb24nKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZS4gQSB2YWx1ZSBpcyBvYmplY3QtbGlrZSBpZiBpdCdzIG5vdCBgbnVsbGBcbiAqIGFuZCBoYXMgYSBgdHlwZW9mYCByZXN1bHQgb2YgXCJvYmplY3RcIi5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZSwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZSh7fSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdExpa2UoWzEsIDIsIDNdKTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShfLm5vb3ApO1xuICogLy8gPT4gZmFsc2VcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShudWxsKTtcbiAqIC8vID0+IGZhbHNlXG4gKi9cbmZ1bmN0aW9uIGlzT2JqZWN0TGlrZSh2YWx1ZSkge1xuICByZXR1cm4gISF2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCc7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgY2xhc3NpZmllZCBhcyBhIGBTeW1ib2xgIHByaW1pdGl2ZSBvciBvYmplY3QuXG4gKlxuICogQHN0YXRpY1xuICogQG1lbWJlck9mIF9cbiAqIEBzaW5jZSA0LjAuMFxuICogQGNhdGVnb3J5IExhbmdcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYSBzeW1ib2wsIGVsc2UgYGZhbHNlYC5cbiAqIEBleGFtcGxlXG4gKlxuICogXy5pc1N5bWJvbChTeW1ib2wuaXRlcmF0b3IpO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNTeW1ib2woJ2FiYycpO1xuICogLy8gPT4gZmFsc2VcbiAqL1xuZnVuY3Rpb24gaXNTeW1ib2wodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PSAnc3ltYm9sJyB8fFxuICAgIChpc09iamVjdExpa2UodmFsdWUpICYmIG9iamVjdFRvU3RyaW5nLmNhbGwodmFsdWUpID09IHN5bWJvbFRhZyk7XG59XG5cbi8qKlxuICogQ29udmVydHMgYHZhbHVlYCB0byBhIG51bWJlci5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcHJvY2Vzcy5cbiAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIG51bWJlci5cbiAqIEBleGFtcGxlXG4gKlxuICogXy50b051bWJlcigzLjIpO1xuICogLy8gPT4gMy4yXG4gKlxuICogXy50b051bWJlcihOdW1iZXIuTUlOX1ZBTFVFKTtcbiAqIC8vID0+IDVlLTMyNFxuICpcbiAqIF8udG9OdW1iZXIoSW5maW5pdHkpO1xuICogLy8gPT4gSW5maW5pdHlcbiAqXG4gKiBfLnRvTnVtYmVyKCczLjInKTtcbiAqIC8vID0+IDMuMlxuICovXG5mdW5jdGlvbiB0b051bWJlcih2YWx1ZSkge1xuICBpZiAodHlwZW9mIHZhbHVlID09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG4gIGlmIChpc1N5bWJvbCh2YWx1ZSkpIHtcbiAgICByZXR1cm4gTkFOO1xuICB9XG4gIGlmIChpc09iamVjdCh2YWx1ZSkpIHtcbiAgICB2YXIgb3RoZXIgPSB0eXBlb2YgdmFsdWUudmFsdWVPZiA9PSAnZnVuY3Rpb24nID8gdmFsdWUudmFsdWVPZigpIDogdmFsdWU7XG4gICAgdmFsdWUgPSBpc09iamVjdChvdGhlcikgPyAob3RoZXIgKyAnJykgOiBvdGhlcjtcbiAgfVxuICBpZiAodHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHZhbHVlID09PSAwID8gdmFsdWUgOiArdmFsdWU7XG4gIH1cbiAgdmFsdWUgPSB2YWx1ZS5yZXBsYWNlKHJlVHJpbSwgJycpO1xuICB2YXIgaXNCaW5hcnkgPSByZUlzQmluYXJ5LnRlc3QodmFsdWUpO1xuICByZXR1cm4gKGlzQmluYXJ5IHx8IHJlSXNPY3RhbC50ZXN0KHZhbHVlKSlcbiAgICA/IGZyZWVQYXJzZUludCh2YWx1ZS5zbGljZSgyKSwgaXNCaW5hcnkgPyAyIDogOClcbiAgICA6IChyZUlzQmFkSGV4LnRlc3QodmFsdWUpID8gTkFOIDogK3ZhbHVlKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB0aHJvdHRsZTtcbiIsInZhciBnO1xuXG4vLyBUaGlzIHdvcmtzIGluIG5vbi1zdHJpY3QgbW9kZVxuZyA9IChmdW5jdGlvbigpIHtcblx0cmV0dXJuIHRoaXM7XG59KSgpO1xuXG50cnkge1xuXHQvLyBUaGlzIHdvcmtzIGlmIGV2YWwgaXMgYWxsb3dlZCAoc2VlIENTUClcblx0ZyA9IGcgfHwgbmV3IEZ1bmN0aW9uKFwicmV0dXJuIHRoaXNcIikoKTtcbn0gY2F0Y2ggKGUpIHtcblx0Ly8gVGhpcyB3b3JrcyBpZiB0aGUgd2luZG93IHJlZmVyZW5jZSBpcyBhdmFpbGFibGVcblx0aWYgKHR5cGVvZiB3aW5kb3cgPT09IFwib2JqZWN0XCIpIGcgPSB3aW5kb3c7XG59XG5cbi8vIGcgY2FuIHN0aWxsIGJlIHVuZGVmaW5lZCwgYnV0IG5vdGhpbmcgdG8gZG8gYWJvdXQgaXQuLi5cbi8vIFdlIHJldHVybiB1bmRlZmluZWQsIGluc3RlYWQgb2Ygbm90aGluZyBoZXJlLCBzbyBpdCdzXG4vLyBlYXNpZXIgdG8gaGFuZGxlIHRoaXMgY2FzZS4gaWYoIWdsb2JhbCkgeyAuLi59XG5cbm1vZHVsZS5leHBvcnRzID0gZztcbiJdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file +!function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=2)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});let o=void 0;function r(e){const t=document.getElementById("vscode-markdown-preview-data");if(t){const n=t.getAttribute(e);if(n)return JSON.parse(n)}throw new Error(`Could not load data for ${e}`)}t.getData=r,t.getSettings=function(){if(o)return o;if(o=r("data-settings"))return o;throw new Error("Could not load settings")}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(0),r="code-line";function i(e){return t=0,n=o.getSettings().lineCount-1,r=e,Math.min(n,Math.max(t,r));var t,n,r}const s=(()=>{let e;return()=>{if(!e){e=[{element:document.body,line:0}];for(const t of document.getElementsByClassName(r)){const n=+t.getAttribute("data-line");isNaN(n)||("CODE"===t.tagName&&t.parentElement&&"PRE"===t.parentElement.tagName?e.push({element:t.parentElement,line:n}):e.push({element:t,line:n}))}}return e}})();function a(e){const t=Math.floor(e),n=s();let o=n[0]||null;for(const e of n){if(e.line===t)return{previous:e,next:void 0};if(e.line>t)return{previous:o,next:e};o=e}return{previous:o}}function c(e){const t=s(),n=e-window.scrollY;let o=-1,r=t.length-1;for(;o+1=n?r=e:o=e}const i=t[r],a=u(i);if(r>=1&&a.top>n){return{previous:t[o],next:i}}return r>1&&rn?{previous:i,next:t[r+1]}:{previous:i}}function u({element:e}){const t=e.getBoundingClientRect(),n=e.querySelector(`.${r}`);if(n){const e=n.getBoundingClientRect(),o=Math.max(1,e.top-t.top);return{top:t.top,height:o}}return t}t.getElementsForSourceLine=a,t.getLineElementsAtPageOffset=c,t.scrollToRevealSourceLine=function(e){if(!o.getSettings().scrollPreviewWithEditor)return;if(e<=0)return void window.scroll(window.scrollX,0);const{previous:t,next:n}=a(e);if(!t)return;let r=0;const i=u(t),s=i.top;if(n&&n.line!==t.line){r=s+(e-t.line)/(n.line-t.line)*(n.element.getBoundingClientRect().top-s)}else{const t=e-Math.floor(e);r=s+i.height*t}window.scroll(window.scrollX,Math.max(1,window.scrollY+r))},t.getEditorLineNumberForPageOffset=function(e){const{previous:t,next:n}=c(e);if(t){const o=u(t),r=e-window.scrollY-o.top;if(n){const e=r/(u(n).top-o.top);return i(t.line+e*(n.line-t.line))}{const e=r/o.height;return i(t.line+e)}}return null},t.getLineElementForFragment=function(e){return s().find(t=>t.element.id===e)}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(3),r=n(4),i=n(5),s=n(1),a=n(0),c=n(6);let u=!0;const l=new o.ActiveLineMarker,f=a.getSettings(),d=acquireVsCodeApi();let g=a.getData("data-state");d.setState(g);const p=i.createPosterForVsCode(d);window.cspAlerter.setPoster(p),window.styleLoadingMonitor.setPoster(p),window.onload=()=>{v()},r.onceDocumentLoaded(()=>{f.scrollPreviewWithEditor&&setTimeout(()=>{if(g.fragment){const e=s.getLineElementForFragment(g.fragment);e&&(u=!0,s.scrollToRevealSourceLine(e.line))}else{const e=+f.line;isNaN(e)||(u=!0,s.scrollToRevealSourceLine(e))}},0)});const m=(()=>{const e=c(e=>{u=!0,s.scrollToRevealSourceLine(e)},50);return(t,n)=>{isNaN(t)||(n.line=t,e(t))}})();let v=c(()=>{const e=[];let t=document.getElementsByTagName("img");if(t){let n;for(n=0;n{u=!0,v()},!0),window.addEventListener("message",e=>{if(e.data.source===f.source)switch(e.data.type){case"onDidChangeTextEditorSelection":l.onDidChangeTextEditorSelection(e.data.line);break;case"updateView":m(e.data.line,f)}},!1),document.addEventListener("dblclick",e=>{if(!f.doubleClickToSwitchToEditor)return;for(let t=e.target;t;t=t.parentNode)if("A"===t.tagName)return;const t=e.pageY,n=s.getEditorLineNumberForPageOffset(t);"number"!=typeof n||isNaN(n)||p.postMessage("didClick",{line:Math.floor(n)})});const h=["http:","https:","mailto:","vscode:","vscode-insiders:"];document.addEventListener("click",e=>{if(!e)return;let t=e.target;for(;t;){if(t.tagName&&"A"===t.tagName&&t.href){if(t.getAttribute("href").startsWith("#"))return;if(h.some(e=>t.href.startsWith(e)))return;const n=t.getAttribute("data-href")||t.getAttribute("href");return/^[a-z\-]+:/i.test(n)?void 0:(p.postMessage("openLink",{href:n}),e.preventDefault(),void e.stopPropagation())}t=t.parentNode}},!0),window.addEventListener("scroll",c(()=>{if(u)u=!1;else{const e=s.getEditorLineNumberForPageOffset(window.scrollY);"number"!=typeof e||isNaN(e)||(p.postMessage("revealLine",{line:e}),g.line=e,d.setState(g))}},50))},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(1);t.ActiveLineMarker=class{onDidChangeTextEditorSelection(e){const{previous:t}=o.getElementsForSourceLine(e);this._update(t&&t.element)}_update(e){this._unmarkActiveElement(this._current),this._markActiveElement(e),this._current=e}_unmarkActiveElement(e){e&&(e.className=e.className.replace(/\bcode-active-line\b/g,""))}_markActiveElement(e){e&&(e.className+=" code-active-line")}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.onceDocumentLoaded=function(e){"loading"===document.readyState||"uninitialized"===document.readyState?document.addEventListener("DOMContentLoaded",e):e()}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const o=n(0);t.createPosterForVsCode=e=>new class{postMessage(t,n){e.postMessage({type:t,source:o.getSettings().source,body:n})}}},function(e,t,n){(function(t){var n="Expected a function",o=NaN,r="[object Symbol]",i=/^\s+|\s+$/g,s=/^[-+]0x[0-9a-f]+$/i,a=/^0b[01]+$/i,c=/^0o[0-7]+$/i,u=parseInt,l="object"==typeof t&&t&&t.Object===Object&&t,f="object"==typeof self&&self&&self.Object===Object&&self,d=l||f||Function("return this")(),g=Object.prototype.toString,p=Math.max,m=Math.min,v=function(){return d.Date.now()};function h(e,t,o){var r,i,s,a,c,u,l=0,f=!1,d=!1,g=!0;if("function"!=typeof e)throw new TypeError(n);function h(t){var n=r,o=i;return r=i=void 0,l=t,a=e.apply(o,n)}function y(e){var n=e-u;return void 0===u||n>=t||n<0||d&&e-l>=s}function E(){var e=v();if(y(e))return M(e);c=setTimeout(E,function(e){var n=t-(e-u);return d?m(n,s-(e-l)):n}(e))}function M(e){return c=void 0,g&&r?h(e):(r=i=void 0,a)}function S(){var e=v(),n=y(e);if(r=arguments,i=this,u=e,n){if(void 0===c)return function(e){return l=e,c=setTimeout(E,t),f?h(e):a}(u);if(d)return c=setTimeout(E,t),h(u)}return void 0===c&&(c=setTimeout(E,t)),a}return t=b(t)||0,w(o)&&(f=!!o.leading,s=(d="maxWait"in o)?p(b(o.maxWait)||0,t):s,g="trailing"in o?!!o.trailing:g),S.cancel=function(){void 0!==c&&clearTimeout(c),l=0,r=u=i=c=void 0},S.flush=function(){return void 0===c?a:M(v())},S}function w(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function b(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&g.call(e)==r}(e))return o;if(w(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=w(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(i,"");var n=a.test(e);return n||c.test(e)?u(e.slice(2),n?2:8):s.test(e)?o:+e}e.exports=function(e,t,o){var r=!0,i=!0;if("function"!=typeof e)throw new TypeError(n);return w(o)&&(r="leading"in o?!!o.leading:r,i="trailing"in o?!!o.trailing:i),h(e,t,{leading:r,maxWait:t,trailing:i})}}).call(this,n(7))},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n}]); +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvc2V0dGluZ3MudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvc2Nyb2xsLXN5bmMudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvYWN0aXZlTGluZU1hcmtlci50cyIsIndlYnBhY2s6Ly8vLi9wcmV2aWV3LXNyYy9ldmVudHMudHMiLCJ3ZWJwYWNrOi8vLy4vcHJldmlldy1zcmMvbWVzc2FnaW5nLnRzIiwid2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9sb2Rhc2gudGhyb3R0bGUvaW5kZXguanMiLCJ3ZWJwYWNrOi8vLyh3ZWJwYWNrKS9idWlsZGluL2dsb2JhbC5qcyJdLCJuYW1lcyI6WyJpbnN0YWxsZWRNb2R1bGVzIiwiX193ZWJwYWNrX3JlcXVpcmVfXyIsIm1vZHVsZUlkIiwiZXhwb3J0cyIsIm1vZHVsZSIsImkiLCJsIiwibW9kdWxlcyIsImNhbGwiLCJtIiwiYyIsImQiLCJuYW1lIiwiZ2V0dGVyIiwibyIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZW51bWVyYWJsZSIsImdldCIsInIiLCJTeW1ib2wiLCJ0b1N0cmluZ1RhZyIsInZhbHVlIiwidCIsIm1vZGUiLCJfX2VzTW9kdWxlIiwibnMiLCJjcmVhdGUiLCJrZXkiLCJiaW5kIiwibiIsIm9iamVjdCIsInByb3BlcnR5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJwIiwicyIsImNhY2hlZFNldHRpbmdzIiwidW5kZWZpbmVkIiwiZ2V0RGF0YSIsImVsZW1lbnQiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwiZGF0YSIsImdldEF0dHJpYnV0ZSIsIkpTT04iLCJwYXJzZSIsIkVycm9yIiwiZ2V0U2V0dGluZ3MiLCJzZXR0aW5nc18xIiwiY29kZUxpbmVDbGFzcyIsImNsYW1wTGluZSIsImxpbmUiLCJtaW4iLCJtYXgiLCJsaW5lQ291bnQiLCJNYXRoIiwiZ2V0Q29kZUxpbmVFbGVtZW50cyIsImVsZW1lbnRzIiwiYm9keSIsImdldEVsZW1lbnRzQnlDbGFzc05hbWUiLCJpc05hTiIsInRhZ05hbWUiLCJwYXJlbnRFbGVtZW50IiwicHVzaCIsImdldEVsZW1lbnRzRm9yU291cmNlTGluZSIsInRhcmdldExpbmUiLCJsaW5lTnVtYmVyIiwiZmxvb3IiLCJsaW5lcyIsInByZXZpb3VzIiwiZW50cnkiLCJuZXh0IiwiZ2V0TGluZUVsZW1lbnRzQXRQYWdlT2Zmc2V0Iiwib2Zmc2V0IiwicG9zaXRpb24iLCJ3aW5kb3ciLCJzY3JvbGxZIiwibG8iLCJoaSIsImxlbmd0aCIsIm1pZCIsImJvdW5kcyIsImdldEVsZW1lbnRCb3VuZHMiLCJ0b3AiLCJoZWlnaHQiLCJoaUVsZW1lbnQiLCJoaUJvdW5kcyIsIm15Qm91bmRzIiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwiY29kZUxpbmVDaGlsZCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGlsZEJvdW5kcyIsInNjcm9sbFRvUmV2ZWFsU291cmNlTGluZSIsInNjcm9sbFByZXZpZXdXaXRoRWRpdG9yIiwic2Nyb2xsIiwic2Nyb2xsWCIsInNjcm9sbFRvIiwicmVjdCIsInByZXZpb3VzVG9wIiwicHJvZ3Jlc3NJbkVsZW1lbnQiLCJnZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCIsInByZXZpb3VzQm91bmRzIiwib2Zmc2V0RnJvbVByZXZpb3VzIiwicHJvZ3Jlc3NCZXR3ZWVuRWxlbWVudHMiLCJwcm9ncmVzc1dpdGhpbkVsZW1lbnQiLCJnZXRMaW5lRWxlbWVudEZvckZyYWdtZW50IiwiZnJhZ21lbnQiLCJmaW5kIiwiaWQiLCJhY3RpdmVMaW5lTWFya2VyXzEiLCJldmVudHNfMSIsIm1lc3NhZ2luZ18xIiwic2Nyb2xsX3N5bmNfMSIsInRocm90dGxlIiwic2Nyb2xsRGlzYWJsZWQiLCJtYXJrZXIiLCJBY3RpdmVMaW5lTWFya2VyIiwic2V0dGluZ3MiLCJ2c2NvZGUiLCJhY3F1aXJlVnNDb2RlQXBpIiwic3RhdGUiLCJzZXRTdGF0ZSIsIm1lc3NhZ2luZyIsImNyZWF0ZVBvc3RlckZvclZzQ29kZSIsImNzcEFsZXJ0ZXIiLCJzZXRQb3N0ZXIiLCJzdHlsZUxvYWRpbmdNb25pdG9yIiwib25sb2FkIiwidXBkYXRlSW1hZ2VTaXplcyIsIm9uY2VEb2N1bWVudExvYWRlZCIsInNldFRpbWVvdXQiLCJpbml0aWFsTGluZSIsIm9uVXBkYXRlVmlldyIsImRvU2Nyb2xsIiwiaW1hZ2VJbmZvIiwiaW1hZ2VzIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJpbWciLCJjbGFzc0xpc3QiLCJjb250YWlucyIsInJlbW92ZSIsIndpZHRoIiwicG9zdE1lc3NhZ2UiLCJhZGRFdmVudExpc3RlbmVyIiwiZXZlbnQiLCJzb3VyY2UiLCJ0eXBlIiwib25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uIiwiZG91YmxlQ2xpY2tUb1N3aXRjaFRvRWRpdG9yIiwibm9kZSIsInRhcmdldCIsInBhcmVudE5vZGUiLCJwYWdlWSIsInBhc3NUaHJvdWdoTGlua1NjaGVtZXMiLCJocmVmIiwic3RhcnRzV2l0aCIsInNvbWUiLCJzY2hlbWUiLCJocmVmVGV4dCIsInRlc3QiLCJwcmV2ZW50RGVmYXVsdCIsInN0b3BQcm9wYWdhdGlvbiIsInRoaXMiLCJfdXBkYXRlIiwiYmVmb3JlIiwiX3VubWFya0FjdGl2ZUVsZW1lbnQiLCJfY3VycmVudCIsIl9tYXJrQWN0aXZlRWxlbWVudCIsImNsYXNzTmFtZSIsInJlcGxhY2UiLCJmIiwicmVhZHlTdGF0ZSIsIkZVTkNfRVJST1JfVEVYVCIsIk5BTiIsInN5bWJvbFRhZyIsInJlVHJpbSIsInJlSXNCYWRIZXgiLCJyZUlzQmluYXJ5IiwicmVJc09jdGFsIiwiZnJlZVBhcnNlSW50IiwicGFyc2VJbnQiLCJmcmVlR2xvYmFsIiwiZ2xvYmFsIiwiZnJlZVNlbGYiLCJzZWxmIiwicm9vdCIsIkZ1bmN0aW9uIiwib2JqZWN0VG9TdHJpbmciLCJ0b1N0cmluZyIsIm5hdGl2ZU1heCIsIm5hdGl2ZU1pbiIsIm5vdyIsIkRhdGUiLCJkZWJvdW5jZSIsImZ1bmMiLCJ3YWl0Iiwib3B0aW9ucyIsImxhc3RBcmdzIiwibGFzdFRoaXMiLCJtYXhXYWl0IiwicmVzdWx0IiwidGltZXJJZCIsImxhc3RDYWxsVGltZSIsImxhc3RJbnZva2VUaW1lIiwibGVhZGluZyIsIm1heGluZyIsInRyYWlsaW5nIiwiVHlwZUVycm9yIiwiaW52b2tlRnVuYyIsInRpbWUiLCJhcmdzIiwidGhpc0FyZyIsImFwcGx5Iiwic2hvdWxkSW52b2tlIiwidGltZVNpbmNlTGFzdENhbGwiLCJ0aW1lckV4cGlyZWQiLCJ0cmFpbGluZ0VkZ2UiLCJyZW1haW5pbmdXYWl0IiwiZGVib3VuY2VkIiwiaXNJbnZva2luZyIsImFyZ3VtZW50cyIsImxlYWRpbmdFZGdlIiwidG9OdW1iZXIiLCJpc09iamVjdCIsImNhbmNlbCIsImNsZWFyVGltZW91dCIsImZsdXNoIiwiaXNPYmplY3RMaWtlIiwiaXNTeW1ib2wiLCJvdGhlciIsInZhbHVlT2YiLCJpc0JpbmFyeSIsInNsaWNlIiwiZyIsImUiXSwibWFwcGluZ3MiOiJhQUNFLElBQUlBLEVBQW1CLEdBR3ZCLFNBQVNDLEVBQW9CQyxHQUc1QixHQUFHRixFQUFpQkUsR0FDbkIsT0FBT0YsRUFBaUJFLEdBQVVDLFFBR25DLElBQUlDLEVBQVNKLEVBQWlCRSxHQUFZLENBQ3pDRyxFQUFHSCxFQUNISSxHQUFHLEVBQ0hILFFBQVMsSUFVVixPQU5BSSxFQUFRTCxHQUFVTSxLQUFLSixFQUFPRCxRQUFTQyxFQUFRQSxFQUFPRCxRQUFTRixHQUcvREcsRUFBT0UsR0FBSSxFQUdKRixFQUFPRCxRQUtmRixFQUFvQlEsRUFBSUYsRUFHeEJOLEVBQW9CUyxFQUFJVixFQUd4QkMsRUFBb0JVLEVBQUksU0FBU1IsRUFBU1MsRUFBTUMsR0FDM0NaLEVBQW9CYSxFQUFFWCxFQUFTUyxJQUNsQ0csT0FBT0MsZUFBZWIsRUFBU1MsRUFBTSxDQUFFSyxZQUFZLEVBQU1DLElBQUtMLEtBS2hFWixFQUFvQmtCLEVBQUksU0FBU2hCLEdBQ1gsb0JBQVhpQixRQUEwQkEsT0FBT0MsYUFDMUNOLE9BQU9DLGVBQWViLEVBQVNpQixPQUFPQyxZQUFhLENBQUVDLE1BQU8sV0FFN0RQLE9BQU9DLGVBQWViLEVBQVMsYUFBYyxDQUFFbUIsT0FBTyxLQVF2RHJCLEVBQW9Cc0IsRUFBSSxTQUFTRCxFQUFPRSxHQUV2QyxHQURVLEVBQVBBLElBQVVGLEVBQVFyQixFQUFvQnFCLElBQy9CLEVBQVBFLEVBQVUsT0FBT0YsRUFDcEIsR0FBVyxFQUFQRSxHQUE4QixpQkFBVkYsR0FBc0JBLEdBQVNBLEVBQU1HLFdBQVksT0FBT0gsRUFDaEYsSUFBSUksRUFBS1gsT0FBT1ksT0FBTyxNQUd2QixHQUZBMUIsRUFBb0JrQixFQUFFTyxHQUN0QlgsT0FBT0MsZUFBZVUsRUFBSSxVQUFXLENBQUVULFlBQVksRUFBTUssTUFBT0EsSUFDdEQsRUFBUEUsR0FBNEIsaUJBQVRGLEVBQW1CLElBQUksSUFBSU0sS0FBT04sRUFBT3JCLEVBQW9CVSxFQUFFZSxFQUFJRSxFQUFLLFNBQVNBLEdBQU8sT0FBT04sRUFBTU0sSUFBUUMsS0FBSyxLQUFNRCxJQUM5SSxPQUFPRixHQUlSekIsRUFBb0I2QixFQUFJLFNBQVMxQixHQUNoQyxJQUFJUyxFQUFTVCxHQUFVQSxFQUFPcUIsV0FDN0IsV0FBd0IsT0FBT3JCLEVBQWdCLFNBQy9DLFdBQThCLE9BQU9BLEdBRXRDLE9BREFILEVBQW9CVSxFQUFFRSxFQUFRLElBQUtBLEdBQzVCQSxHQUlSWixFQUFvQmEsRUFBSSxTQUFTaUIsRUFBUUMsR0FBWSxPQUFPakIsT0FBT2tCLFVBQVVDLGVBQWUxQixLQUFLdUIsRUFBUUMsSUFHekcvQixFQUFvQmtDLEVBQUksR0FJakJsQyxFQUFvQkEsRUFBb0JtQyxFQUFJLEcsK0JDN0VyRHJCLE9BQU9DLGVBQWViLEVBQVMsYUFBYyxDQUFFbUIsT0FBTyxJQUN0RCxJQUFJZSxPQUFpQkMsRUFDckIsU0FBU0MsRUFBUVgsR0FDYixNQUFNWSxFQUFVQyxTQUFTQyxlQUFlLGdDQUN4QyxHQUFJRixFQUFTLENBQ1QsTUFBTUcsRUFBT0gsRUFBUUksYUFBYWhCLEdBQ2xDLEdBQUllLEVBQ0EsT0FBT0UsS0FBS0MsTUFBTUgsR0FHMUIsTUFBTSxJQUFJSSxNQUFNLDJCQUEyQm5CLEtBRS9DekIsRUFBUW9DLFFBQVVBLEVBV2xCcEMsRUFBUTZDLFlBVlIsV0FDSSxHQUFJWCxFQUNBLE9BQU9BLEVBR1gsR0FEQUEsRUFBaUJFLEVBQVEsaUJBRXJCLE9BQU9GLEVBRVgsTUFBTSxJQUFJVSxNQUFNLDZCLDZCQ3JCcEJoQyxPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sSUFDdEQsTUFBTTJCLEVBQWEsRUFBUSxHQUNyQkMsRUFBZ0IsWUFJdEIsU0FBU0MsRUFBVUMsR0FDZixPQUpXQyxFQUlFLEVBSkdDLEVBSUFMLEVBQVdELGNBQWNPLFVBQVksRUFKaENqQyxFQUltQzhCLEVBSGpESSxLQUFLSCxJQUFJQyxFQUFLRSxLQUFLRixJQUFJRCxFQUFLL0IsSUFEdkMsSUFBZStCLEVBQUtDLEVBQUtoQyxFQU16QixNQUFNbUMsRUFBc0IsTUFDeEIsSUFBSUMsRUFDSixNQUFPLEtBQ0gsSUFBS0EsRUFBVSxDQUNYQSxFQUFXLENBQUMsQ0FBRWxCLFFBQVNDLFNBQVNrQixLQUFNUCxLQUFNLElBQzVDLElBQUssTUFBTVosS0FBV0MsU0FBU21CLHVCQUF1QlYsR0FBZ0IsQ0FDbEUsTUFBTUUsR0FBUVosRUFBUUksYUFBYSxhQUMvQmlCLE1BQU1ULEtBR2MsU0FBcEJaLEVBQVFzQixTQUFzQnRCLEVBQVF1QixlQUFtRCxRQUFsQ3ZCLEVBQVF1QixjQUFjRCxRQUc3RUosRUFBU00sS0FBSyxDQUFFeEIsUUFBU0EsRUFBUXVCLGNBQWVYLFNBR2hETSxFQUFTTSxLQUFLLENBQUV4QixRQUFTQSxFQUFTWSxXQUk5QyxPQUFPTSxJQXBCYSxHQTZCNUIsU0FBU08sRUFBeUJDLEdBQzlCLE1BQU1DLEVBQWFYLEtBQUtZLE1BQU1GLEdBQ3hCRyxFQUFRWixJQUNkLElBQUlhLEVBQVdELEVBQU0sSUFBTSxLQUMzQixJQUFLLE1BQU1FLEtBQVNGLEVBQU8sQ0FDdkIsR0FBSUUsRUFBTW5CLE9BQVNlLEVBQ2YsTUFBTyxDQUFFRyxTQUFVQyxFQUFPQyxVQUFNbEMsR0FFL0IsR0FBSWlDLEVBQU1uQixLQUFPZSxFQUNsQixNQUFPLENBQUVHLFdBQVVFLEtBQU1ELEdBRTdCRCxFQUFXQyxFQUVmLE1BQU8sQ0FBRUQsWUFNYixTQUFTRyxFQUE0QkMsR0FDakMsTUFBTUwsRUFBUVosSUFDUmtCLEVBQVdELEVBQVNFLE9BQU9DLFFBQ2pDLElBQUlDLEdBQU0sRUFDTkMsRUFBS1YsRUFBTVcsT0FBUyxFQUN4QixLQUFPRixFQUFLLEVBQUlDLEdBQUksQ0FDaEIsTUFBTUUsRUFBTXpCLEtBQUtZLE9BQU9VLEVBQUtDLEdBQU0sR0FDN0JHLEVBQVNDLEVBQWlCZCxFQUFNWSxJQUNsQ0MsRUFBT0UsSUFBTUYsRUFBT0csUUFBVVYsRUFDOUJJLEVBQUtFLEVBR0xILEVBQUtHLEVBR2IsTUFBTUssRUFBWWpCLEVBQU1VLEdBQ2xCUSxFQUFXSixFQUFpQkcsR0FDbEMsR0FBSVAsR0FBTSxHQUFLUSxFQUFTSCxJQUFNVCxFQUFVLENBRXBDLE1BQU8sQ0FBRUwsU0FEU0QsRUFBTVMsR0FDTU4sS0FBTWMsR0FFeEMsT0FBSVAsRUFBSyxHQUFLQSxFQUFLVixFQUFNVyxRQUFVTyxFQUFTSCxJQUFNRyxFQUFTRixPQUFTVixFQUN6RCxDQUFFTCxTQUFVZ0IsRUFBV2QsS0FBTUgsRUFBTVUsRUFBSyxJQUU1QyxDQUFFVCxTQUFVZ0IsR0FHdkIsU0FBU0gsR0FBaUIsUUFBRTNDLElBQ3hCLE1BQU1nRCxFQUFXaEQsRUFBUWlELHdCQUduQkMsRUFBZ0JsRCxFQUFRbUQsY0FBYyxJQUFJekMsS0FDaEQsR0FBSXdDLEVBQWUsQ0FDZixNQUFNRSxFQUFjRixFQUFjRCx3QkFDNUJKLEVBQVM3QixLQUFLRixJQUFJLEVBQUlzQyxFQUFZUixJQUFNSSxFQUFTSixLQUN2RCxNQUFPLENBQ0hBLElBQUtJLEVBQVNKLElBQ2RDLE9BQVFBLEdBR2hCLE9BQU9HLEVBNUNYckYsRUFBUThELHlCQUEyQkEsRUE4Qm5DOUQsRUFBUXNFLDRCQUE4QkEsRUE4Q3RDdEUsRUFBUTBGLHlCQTNCUixTQUFrQ3pDLEdBQzlCLElBQUtILEVBQVdELGNBQWM4Qyx3QkFDMUIsT0FFSixHQUFJMUMsR0FBUSxFQUVSLFlBREF3QixPQUFPbUIsT0FBT25CLE9BQU9vQixRQUFTLEdBR2xDLE1BQU0sU0FBRTFCLEVBQVEsS0FBRUUsR0FBU1AsRUFBeUJiLEdBQ3BELElBQUtrQixFQUNELE9BRUosSUFBSTJCLEVBQVcsRUFDZixNQUFNQyxFQUFPZixFQUFpQmIsR0FDeEI2QixFQUFjRCxFQUFLZCxJQUN6QixHQUFJWixHQUFRQSxFQUFLcEIsT0FBU2tCLEVBQVNsQixLQUFNLENBSXJDNkMsRUFBV0UsR0FGYy9DLEVBQU9rQixFQUFTbEIsT0FBU29CLEVBQUtwQixLQUFPa0IsRUFBU2xCLE9BQ2pEb0IsRUFBS2hDLFFBQVFpRCx3QkFBd0JMLElBQU1lLE9BR2hFLENBQ0QsTUFBTUMsRUFBb0JoRCxFQUFPSSxLQUFLWSxNQUFNaEIsR0FDNUM2QyxFQUFXRSxFQUFlRCxFQUFLYixPQUFTZSxFQUU1Q3hCLE9BQU9tQixPQUFPbkIsT0FBT29CLFFBQVN4QyxLQUFLRixJQUFJLEVBQUdzQixPQUFPQyxRQUFVb0IsS0FxQi9EOUYsRUFBUWtHLGlDQWxCUixTQUEwQzNCLEdBQ3RDLE1BQU0sU0FBRUosRUFBUSxLQUFFRSxHQUFTQyxFQUE0QkMsR0FDdkQsR0FBSUosRUFBVSxDQUNWLE1BQU1nQyxFQUFpQm5CLEVBQWlCYixHQUNsQ2lDLEVBQXNCN0IsRUFBU0UsT0FBT0MsUUFBVXlCLEVBQWVsQixJQUNyRSxHQUFJWixFQUFNLENBQ04sTUFBTWdDLEVBQTBCRCxHQUFzQnBCLEVBQWlCWCxHQUFNWSxJQUFNa0IsRUFBZWxCLEtBRWxHLE9BQU9qQyxFQURNbUIsRUFBU2xCLEtBQU9vRCxHQUEyQmhDLEVBQUtwQixLQUFPa0IsRUFBU2xCLE9BRzVFLENBQ0QsTUFBTXFELEVBQXdCRixFQUFzQkQsRUFBcUIsT0FFekUsT0FBT25ELEVBRE1tQixFQUFTbEIsS0FBT3FELElBSXJDLE9BQU8sTUFXWHRHLEVBQVF1RywwQkFMUixTQUFtQ0MsR0FDL0IsT0FBT2xELElBQXNCbUQsS0FBTXBFLEdBQ3hCQSxFQUFRQSxRQUFRcUUsS0FBT0YsSyw2QkMxSnRDNUYsT0FBT0MsZUFBZWIsRUFBUyxhQUFjLENBQUVtQixPQUFPLElBQ3RELE1BQU13RixFQUFxQixFQUFRLEdBQzdCQyxFQUFXLEVBQVEsR0FDbkJDLEVBQWMsRUFBUSxHQUN0QkMsRUFBZ0IsRUFBUSxHQUN4QmhFLEVBQWEsRUFBUSxHQUNyQmlFLEVBQVcsRUFBUSxHQUN6QixJQUFJQyxHQUFpQixFQUNyQixNQUFNQyxFQUFTLElBQUlOLEVBQW1CTyxpQkFDaENDLEVBQVdyRSxFQUFXRCxjQUN0QnVFLEVBQVNDLG1CQUVmLElBQUlDLEVBQVF4RSxFQUFXVixRQUFRLGNBQy9CZ0YsRUFBT0csU0FBU0QsR0FDaEIsTUFBTUUsRUFBWVgsRUFBWVksc0JBQXNCTCxHQUNwRDNDLE9BQU9pRCxXQUFXQyxVQUFVSCxHQUM1Qi9DLE9BQU9tRCxvQkFBb0JELFVBQVVILEdBQ3JDL0MsT0FBT29ELE9BQVMsS0FDWkMsS0FFSmxCLEVBQVNtQixtQkFBbUIsS0FDcEJaLEVBQVN4Qix5QkFDVHFDLFdBQVcsS0FFUCxHQUFJVixFQUFNZCxTQUFVLENBQ2hCLE1BQU1uRSxFQUFVeUUsRUFBY1AsMEJBQTBCZSxFQUFNZCxVQUMxRG5FLElBQ0EyRSxHQUFpQixFQUNqQkYsRUFBY3BCLHlCQUF5QnJELEVBQVFZLFdBR2xELENBQ0QsTUFBTWdGLEdBQWVkLEVBQVNsRSxLQUN6QlMsTUFBTXVFLEtBQ1BqQixHQUFpQixFQUNqQkYsRUFBY3BCLHlCQUF5QnVDLE1BR2hELEtBR1gsTUFBTUMsRUFBZSxNQUNqQixNQUFNQyxFQUFXcEIsRUFBVTlELElBQ3ZCK0QsR0FBaUIsRUFDakJGLEVBQWNwQix5QkFBeUJ6QyxJQUN4QyxJQUNILE1BQU8sQ0FBQ0EsRUFBTWtFLEtBQ0x6RCxNQUFNVCxLQUNQa0UsRUFBU2xFLEtBQU9BLEVBQ2hCa0YsRUFBU2xGLE1BUkEsR0FZckIsSUFBSTZFLEVBQW1CZixFQUFTLEtBQzVCLE1BQU1xQixFQUFZLEdBQ2xCLElBQUlDLEVBQVMvRixTQUFTZ0cscUJBQXFCLE9BQzNDLEdBQUlELEVBQVEsQ0FDUixJQUFJbkksRUFDSixJQUFLQSxFQUFJLEVBQUdBLEVBQUltSSxFQUFPeEQsT0FBUTNFLElBQUssQ0FDaEMsTUFBTXFJLEVBQU1GLEVBQU9uSSxHQUNmcUksRUFBSUMsVUFBVUMsU0FBUyxZQUN2QkYsRUFBSUMsVUFBVUUsT0FBTyxXQUV6Qk4sRUFBVXZFLEtBQUssQ0FDWDZDLEdBQUk2QixFQUFJN0IsR0FDUnhCLE9BQVFxRCxFQUFJckQsT0FDWnlELE1BQU9KLEVBQUlJLFFBR25CbkIsRUFBVW9CLFlBQVksa0JBQW1CUixLQUU5QyxJQUNIM0QsT0FBT29FLGlCQUFpQixTQUFVLEtBQzlCN0IsR0FBaUIsRUFDakJjLE1BQ0QsR0FDSHJELE9BQU9vRSxpQkFBaUIsVUFBV0MsSUFDL0IsR0FBSUEsRUFBTXRHLEtBQUt1RyxTQUFXNUIsRUFBUzRCLE9BR25DLE9BQVFELEVBQU10RyxLQUFLd0csTUFDZixJQUFLLGlDQUNEL0IsRUFBT2dDLCtCQUErQkgsRUFBTXRHLEtBQUtTLE1BQ2pELE1BQ0osSUFBSyxhQUNEaUYsRUFBYVksRUFBTXRHLEtBQUtTLEtBQU1rRSxNQUd2QyxHQUNIN0UsU0FBU3VHLGlCQUFpQixXQUFZQyxJQUNsQyxJQUFLM0IsRUFBUytCLDRCQUNWLE9BR0osSUFBSyxJQUFJQyxFQUFPTCxFQUFNTSxPQUFRRCxFQUFNQSxFQUFPQSxFQUFLRSxXQUM1QyxHQUFxQixNQUFqQkYsRUFBS3hGLFFBQ0wsT0FHUixNQUFNWSxFQUFTdUUsRUFBTVEsTUFDZnJHLEVBQU82RCxFQUFjWixpQ0FBaUMzQixHQUN4QyxpQkFBVHRCLEdBQXNCUyxNQUFNVCxJQUNuQ3VFLEVBQVVvQixZQUFZLFdBQVksQ0FBRTNGLEtBQU1JLEtBQUtZLE1BQU1oQixPQUc3RCxNQUFNc0csRUFBeUIsQ0FBQyxRQUFTLFNBQVUsVUFBVyxVQUFXLG9CQUN6RWpILFNBQVN1RyxpQkFBaUIsUUFBU0MsSUFDL0IsSUFBS0EsRUFDRCxPQUVKLElBQUlLLEVBQU9MLEVBQU1NLE9BQ2pCLEtBQU9ELEdBQU0sQ0FDVCxHQUFJQSxFQUFLeEYsU0FBNEIsTUFBakJ3RixFQUFLeEYsU0FBbUJ3RixFQUFLSyxLQUFNLENBQ25ELEdBQUlMLEVBQUsxRyxhQUFhLFFBQVFnSCxXQUFXLEtBQ3JDLE9BR0osR0FBSUYsRUFBdUJHLEtBQUtDLEdBQVVSLEVBQUtLLEtBQUtDLFdBQVdFLElBQzNELE9BRUosTUFBTUMsRUFBV1QsRUFBSzFHLGFBQWEsY0FBZ0IwRyxFQUFLMUcsYUFBYSxRQUVyRSxNQUFLLGNBQWNvSCxLQUFLRCxRQU14QixHQUxJcEMsRUFBVW9CLFlBQVksV0FBWSxDQUFFWSxLQUFNSSxJQUMxQ2QsRUFBTWdCLHNCQUNOaEIsRUFBTWlCLG1CQUtkWixFQUFPQSxFQUFLRSxjQUVqQixHQUNINUUsT0FBT29FLGlCQUFpQixTQUFVOUIsRUFBUyxLQUN2QyxHQUFJQyxFQUNBQSxHQUFpQixNQUVoQixDQUNELE1BQU0vRCxFQUFPNkQsRUFBY1osaUNBQWlDekIsT0FBT0MsU0FDL0MsaUJBQVR6QixHQUFzQlMsTUFBTVQsS0FDbkN1RSxFQUFVb0IsWUFBWSxhQUFjLENBQUUzRixTQUN0Q3FFLEVBQU1yRSxLQUFPQSxFQUNibUUsRUFBT0csU0FBU0QsTUFHekIsTSw2QkNySkgxRyxPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sSUFLdEQsTUFBTTJGLEVBQWdCLEVBQVEsR0F3QjlCOUcsRUFBUWtILGlCQXZCUixNQUNJLCtCQUErQmpFLEdBQzNCLE1BQU0sU0FBRWtCLEdBQWEyQyxFQUFjaEQseUJBQXlCYixHQUM1RCtHLEtBQUtDLFFBQVE5RixHQUFZQSxFQUFTOUIsU0FFdEMsUUFBUTZILEdBQ0pGLEtBQUtHLHFCQUFxQkgsS0FBS0ksVUFDL0JKLEtBQUtLLG1CQUFtQkgsR0FDeEJGLEtBQUtJLFNBQVdGLEVBRXBCLHFCQUFxQjdILEdBQ1pBLElBR0xBLEVBQVFpSSxVQUFZakksRUFBUWlJLFVBQVVDLFFBQVEsd0JBQXlCLEtBRTNFLG1CQUFtQmxJLEdBQ1ZBLElBR0xBLEVBQVFpSSxXQUFhLHdCLDZCQ3RCN0IxSixPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sSUFTdERuQixFQUFRK0gsbUJBUlIsU0FBNEJ5QyxHQUNJLFlBQXhCbEksU0FBU21JLFlBQW9ELGtCQUF4Qm5JLFNBQVNtSSxXQUM5Q25JLFNBQVN1RyxpQkFBaUIsbUJBQW9CMkIsR0FHOUNBLE0sNkJDTlI1SixPQUFPQyxlQUFlYixFQUFTLGFBQWMsQ0FBRW1CLE9BQU8sSUFDdEQsTUFBTTJCLEVBQWEsRUFBUSxHQUMzQjlDLEVBQVF5SCxzQkFBeUJMLEdBQ3RCLElBQUksTUFDUCxZQUFZNEIsRUFBTXhGLEdBQ2Q0RCxFQUFPd0IsWUFBWSxDQUNmSSxPQUNBRCxPQUFRakcsRUFBV0QsY0FBY2tHLE9BQ2pDdkYsWSxpQkNiaEIsWUFVQSxJQUFJa0gsRUFBa0Isc0JBR2xCQyxFQUFNLElBR05DLEVBQVksa0JBR1pDLEVBQVMsYUFHVEMsRUFBYSxxQkFHYkMsRUFBYSxhQUdiQyxFQUFZLGNBR1pDLEVBQWVDLFNBR2ZDLEVBQThCLGlCQUFWQyxHQUFzQkEsR0FBVUEsRUFBT3hLLFNBQVdBLFFBQVV3SyxFQUdoRkMsRUFBMEIsaUJBQVJDLE1BQW9CQSxNQUFRQSxLQUFLMUssU0FBV0EsUUFBVTBLLEtBR3hFQyxFQUFPSixHQUFjRSxHQUFZRyxTQUFTLGNBQVRBLEdBVWpDQyxFQVBjN0ssT0FBT2tCLFVBT1E0SixTQUc3QkMsRUFBWXRJLEtBQUtGLElBQ2pCeUksRUFBWXZJLEtBQUtILElBa0JqQjJJLEVBQU0sV0FDUixPQUFPTixFQUFLTyxLQUFLRCxPQXlEbkIsU0FBU0UsRUFBU0MsRUFBTUMsRUFBTUMsR0FDNUIsSUFBSUMsRUFDQUMsRUFDQUMsRUFDQUMsRUFDQUMsRUFDQUMsRUFDQUMsRUFBaUIsRUFDakJDLEdBQVUsRUFDVkMsR0FBUyxFQUNUQyxHQUFXLEVBRWYsR0FBbUIsbUJBQVJaLEVBQ1QsTUFBTSxJQUFJYSxVQUFVbkMsR0FVdEIsU0FBU29DLEVBQVdDLEdBQ2xCLElBQUlDLEVBQU9iLEVBQ1BjLEVBQVViLEVBS2QsT0FIQUQsRUFBV0MsT0FBV2pLLEVBQ3RCc0ssRUFBaUJNLEVBQ2pCVCxFQUFTTixFQUFLa0IsTUFBTUQsRUFBU0QsR0FxQi9CLFNBQVNHLEVBQWFKLEdBQ3BCLElBQUlLLEVBQW9CTCxFQUFPUCxFQU0vQixZQUF5QnJLLElBQWpCcUssR0FBK0JZLEdBQXFCbkIsR0FDekRtQixFQUFvQixHQUFPVCxHQU5KSSxFQUFPTixHQU04QkosRUFHakUsU0FBU2dCLElBQ1AsSUFBSU4sRUFBT2xCLElBQ1gsR0FBSXNCLEVBQWFKLEdBQ2YsT0FBT08sRUFBYVAsR0FHdEJSLEVBQVV2RSxXQUFXcUYsRUF6QnZCLFNBQXVCTixHQUNyQixJQUVJVCxFQUFTTCxHQUZXYyxFQUFPUCxHQUkvQixPQUFPRyxFQUFTZixFQUFVVSxFQUFRRCxHQUhSVSxFQUFPTixJQUdrQ0gsRUFvQmhDaUIsQ0FBY1IsSUFHbkQsU0FBU08sRUFBYVAsR0FLcEIsT0FKQVIsT0FBVXBLLEVBSU55SyxHQUFZVCxFQUNQVyxFQUFXQyxJQUVwQlosRUFBV0MsT0FBV2pLLEVBQ2ZtSyxHQWVULFNBQVNrQixJQUNQLElBQUlULEVBQU9sQixJQUNQNEIsRUFBYU4sRUFBYUosR0FNOUIsR0FKQVosRUFBV3VCLFVBQ1h0QixFQUFXcEMsS0FDWHdDLEVBQWVPLEVBRVhVLEVBQVksQ0FDZCxRQUFnQnRMLElBQVpvSyxFQUNGLE9BdkVOLFNBQXFCUSxHQU1uQixPQUpBTixFQUFpQk0sRUFFakJSLEVBQVV2RSxXQUFXcUYsRUFBY3BCLEdBRTVCUyxFQUFVSSxFQUFXQyxHQUFRVCxFQWlFekJxQixDQUFZbkIsR0FFckIsR0FBSUcsRUFHRixPQURBSixFQUFVdkUsV0FBV3FGLEVBQWNwQixHQUM1QmEsRUFBV04sR0FNdEIsWUFIZ0JySyxJQUFab0ssSUFDRkEsRUFBVXZFLFdBQVdxRixFQUFjcEIsSUFFOUJLLEVBSVQsT0F4R0FMLEVBQU8yQixFQUFTM0IsSUFBUyxFQUNyQjRCLEVBQVMzQixLQUNYUSxJQUFZUixFQUFRUSxRQUVwQkwsR0FEQU0sRUFBUyxZQUFhVCxHQUNIUCxFQUFVaUMsRUFBUzFCLEVBQVFHLFVBQVksRUFBR0osR0FBUUksRUFDckVPLEVBQVcsYUFBY1YsSUFBWUEsRUFBUVUsU0FBV0EsR0FpRzFEWSxFQUFVTSxPQW5DVixnQkFDa0IzTCxJQUFab0ssR0FDRndCLGFBQWF4QixHQUVmRSxFQUFpQixFQUNqQk4sRUFBV0ssRUFBZUosRUFBV0csT0FBVXBLLEdBK0JqRHFMLEVBQVVRLE1BNUJWLFdBQ0UsWUFBbUI3TCxJQUFab0ssRUFBd0JELEVBQVNnQixFQUFhekIsTUE0QmhEMkIsRUEwRlQsU0FBU0ssRUFBUzFNLEdBQ2hCLElBQUk2SCxTQUFjN0gsRUFDbEIsUUFBU0EsSUFBa0IsVUFBUjZILEdBQTRCLFlBQVJBLEdBNEV6QyxTQUFTNEUsRUFBU3pNLEdBQ2hCLEdBQW9CLGlCQUFUQSxFQUNULE9BQU9BLEVBRVQsR0FoQ0YsU0FBa0JBLEdBQ2hCLE1BQXVCLGlCQUFUQSxHQXRCaEIsU0FBc0JBLEdBQ3BCLFFBQVNBLEdBQXlCLGlCQUFUQSxFQXNCdEI4TSxDQUFhOU0sSUFBVXNLLEVBQWVwTCxLQUFLYyxJQUFVeUosRUE4QnBEc0QsQ0FBUy9NLEdBQ1gsT0FBT3dKLEVBRVQsR0FBSWtELEVBQVMxTSxHQUFRLENBQ25CLElBQUlnTixFQUFnQyxtQkFBakJoTixFQUFNaU4sUUFBd0JqTixFQUFNaU4sVUFBWWpOLEVBQ25FQSxFQUFRME0sRUFBU00sR0FBVUEsRUFBUSxHQUFNQSxFQUUzQyxHQUFvQixpQkFBVGhOLEVBQ1QsT0FBaUIsSUFBVkEsRUFBY0EsR0FBU0EsRUFFaENBLEVBQVFBLEVBQU1vSixRQUFRTSxFQUFRLElBQzlCLElBQUl3RCxFQUFXdEQsRUFBV2xCLEtBQUsxSSxHQUMvQixPQUFRa04sR0FBWXJELEVBQVVuQixLQUFLMUksR0FDL0I4SixFQUFhOUosRUFBTW1OLE1BQU0sR0FBSUQsRUFBVyxFQUFJLEdBQzNDdkQsRUFBV2pCLEtBQUsxSSxHQUFTd0osR0FBT3hKLEVBR3ZDbEIsRUFBT0QsUUE5SVAsU0FBa0JnTSxFQUFNQyxFQUFNQyxHQUM1QixJQUFJUSxHQUFVLEVBQ1ZFLEdBQVcsRUFFZixHQUFtQixtQkFBUlosRUFDVCxNQUFNLElBQUlhLFVBQVVuQyxHQU10QixPQUpJbUQsRUFBUzNCLEtBQ1hRLEVBQVUsWUFBYVIsSUFBWUEsRUFBUVEsUUFBVUEsRUFDckRFLEVBQVcsYUFBY1YsSUFBWUEsRUFBUVUsU0FBV0EsR0FFbkRiLEVBQVNDLEVBQU1DLEVBQU0sQ0FDMUIsUUFBV1MsRUFDWCxRQUFXVCxFQUNYLFNBQVlXLE8sK0JDdFRoQixJQUFJMkIsRUFHSkEsRUFBSSxXQUNILE9BQU92RSxLQURKLEdBSUosSUFFQ3VFLEVBQUlBLEdBQUssSUFBSS9DLFNBQVMsY0FBYixHQUNSLE1BQU9nRCxHQUVjLGlCQUFYL0osU0FBcUI4SixFQUFJOUosUUFPckN4RSxFQUFPRCxRQUFVdU8iLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VzQ29udGVudCI6WyIgXHQvLyBUaGUgbW9kdWxlIGNhY2hlXG4gXHR2YXIgaW5zdGFsbGVkTW9kdWxlcyA9IHt9O1xuXG4gXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuIFx0ZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXG4gXHRcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxuIFx0XHRpZihpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSkge1xuIFx0XHRcdHJldHVybiBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXS5leHBvcnRzO1xuIFx0XHR9XG4gXHRcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG4gXHRcdHZhciBtb2R1bGUgPSBpbnN0YWxsZWRNb2R1bGVzW21vZHVsZUlkXSA9IHtcbiBcdFx0XHRpOiBtb2R1bGVJZCxcbiBcdFx0XHRsOiBmYWxzZSxcbiBcdFx0XHRleHBvcnRzOiB7fVxuIFx0XHR9O1xuXG4gXHRcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuIFx0XHRtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuIFx0XHQvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG4gXHRcdG1vZHVsZS5sID0gdHJ1ZTtcblxuIFx0XHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuIFx0XHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG4gXHR9XG5cblxuIFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcbiBcdF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlIGNhY2hlXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xuXG4gXHQvLyBkZWZpbmUgZ2V0dGVyIGZ1bmN0aW9uIGZvciBoYXJtb255IGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uZCA9IGZ1bmN0aW9uKGV4cG9ydHMsIG5hbWUsIGdldHRlcikge1xuIFx0XHRpZighX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIG5hbWUpKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIG5hbWUsIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBnZXR0ZXIgfSk7XG4gXHRcdH1cbiBcdH07XG5cbiBcdC8vIGRlZmluZSBfX2VzTW9kdWxlIG9uIGV4cG9ydHNcbiBcdF9fd2VicGFja19yZXF1aXJlX18uciA9IGZ1bmN0aW9uKGV4cG9ydHMpIHtcbiBcdFx0aWYodHlwZW9mIFN5bWJvbCAhPT0gJ3VuZGVmaW5lZCcgJiYgU3ltYm9sLnRvU3RyaW5nVGFnKSB7XG4gXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFN5bWJvbC50b1N0cmluZ1RhZywgeyB2YWx1ZTogJ01vZHVsZScgfSk7XG4gXHRcdH1cbiBcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcbiBcdH07XG5cbiBcdC8vIGNyZWF0ZSBhIGZha2UgbmFtZXNwYWNlIG9iamVjdFxuIFx0Ly8gbW9kZSAmIDE6IHZhbHVlIGlzIGEgbW9kdWxlIGlkLCByZXF1aXJlIGl0XG4gXHQvLyBtb2RlICYgMjogbWVyZ2UgYWxsIHByb3BlcnRpZXMgb2YgdmFsdWUgaW50byB0aGUgbnNcbiBcdC8vIG1vZGUgJiA0OiByZXR1cm4gdmFsdWUgd2hlbiBhbHJlYWR5IG5zIG9iamVjdFxuIFx0Ly8gbW9kZSAmIDh8MTogYmVoYXZlIGxpa2UgcmVxdWlyZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy50ID0gZnVuY3Rpb24odmFsdWUsIG1vZGUpIHtcbiBcdFx0aWYobW9kZSAmIDEpIHZhbHVlID0gX193ZWJwYWNrX3JlcXVpcmVfXyh2YWx1ZSk7XG4gXHRcdGlmKG1vZGUgJiA4KSByZXR1cm4gdmFsdWU7XG4gXHRcdGlmKChtb2RlICYgNCkgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAmJiB2YWx1ZS5fX2VzTW9kdWxlKSByZXR1cm4gdmFsdWU7XG4gXHRcdHZhciBucyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG4gXHRcdF9fd2VicGFja19yZXF1aXJlX18ucihucyk7XG4gXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShucywgJ2RlZmF1bHQnLCB7IGVudW1lcmFibGU6IHRydWUsIHZhbHVlOiB2YWx1ZSB9KTtcbiBcdFx0aWYobW9kZSAmIDIgJiYgdHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSBmb3IodmFyIGtleSBpbiB2YWx1ZSkgX193ZWJwYWNrX3JlcXVpcmVfXy5kKG5zLCBrZXksIGZ1bmN0aW9uKGtleSkgeyByZXR1cm4gdmFsdWVba2V5XTsgfS5iaW5kKG51bGwsIGtleSkpO1xuIFx0XHRyZXR1cm4gbnM7XG4gXHR9O1xuXG4gXHQvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24obW9kdWxlKSB7XG4gXHRcdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuIFx0XHRcdGZ1bmN0aW9uIGdldERlZmF1bHQoKSB7IHJldHVybiBtb2R1bGVbJ2RlZmF1bHQnXTsgfSA6XG4gXHRcdFx0ZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHsgcmV0dXJuIG1vZHVsZTsgfTtcbiBcdFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuIFx0XHRyZXR1cm4gZ2V0dGVyO1xuIFx0fTtcblxuIFx0Ly8gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm8gPSBmdW5jdGlvbihvYmplY3QsIHByb3BlcnR5KSB7IHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wZXJ0eSk7IH07XG5cbiBcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLnAgPSBcIlwiO1xuXG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oX193ZWJwYWNrX3JlcXVpcmVfXy5zID0gMik7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xubGV0IGNhY2hlZFNldHRpbmdzID0gdW5kZWZpbmVkO1xuZnVuY3Rpb24gZ2V0RGF0YShrZXkpIHtcbiAgICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ZzY29kZS1tYXJrZG93bi1wcmV2aWV3LWRhdGEnKTtcbiAgICBpZiAoZWxlbWVudCkge1xuICAgICAgICBjb25zdCBkYXRhID0gZWxlbWVudC5nZXRBdHRyaWJ1dGUoa2V5KTtcbiAgICAgICAgaWYgKGRhdGEpIHtcbiAgICAgICAgICAgIHJldHVybiBKU09OLnBhcnNlKGRhdGEpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgQ291bGQgbm90IGxvYWQgZGF0YSBmb3IgJHtrZXl9YCk7XG59XG5leHBvcnRzLmdldERhdGEgPSBnZXREYXRhO1xuZnVuY3Rpb24gZ2V0U2V0dGluZ3MoKSB7XG4gICAgaWYgKGNhY2hlZFNldHRpbmdzKSB7XG4gICAgICAgIHJldHVybiBjYWNoZWRTZXR0aW5ncztcbiAgICB9XG4gICAgY2FjaGVkU2V0dGluZ3MgPSBnZXREYXRhKCdkYXRhLXNldHRpbmdzJyk7XG4gICAgaWYgKGNhY2hlZFNldHRpbmdzKSB7XG4gICAgICAgIHJldHVybiBjYWNoZWRTZXR0aW5ncztcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDb3VsZCBub3QgbG9hZCBzZXR0aW5ncycpO1xufVxuZXhwb3J0cy5nZXRTZXR0aW5ncyA9IGdldFNldHRpbmdzO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG4vKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICogIENvcHlyaWdodCAoYykgTWljcm9zb2Z0IENvcnBvcmF0aW9uLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICogIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgTGljZW5zZS4gU2VlIExpY2Vuc2UudHh0IGluIHRoZSBwcm9qZWN0IHJvb3QgZm9yIGxpY2Vuc2UgaW5mb3JtYXRpb24uXG4gKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbmNvbnN0IHNldHRpbmdzXzEgPSByZXF1aXJlKFwiLi9zZXR0aW5nc1wiKTtcbmNvbnN0IGNvZGVMaW5lQ2xhc3MgPSAnY29kZS1saW5lJztcbmZ1bmN0aW9uIGNsYW1wKG1pbiwgbWF4LCB2YWx1ZSkge1xuICAgIHJldHVybiBNYXRoLm1pbihtYXgsIE1hdGgubWF4KG1pbiwgdmFsdWUpKTtcbn1cbmZ1bmN0aW9uIGNsYW1wTGluZShsaW5lKSB7XG4gICAgcmV0dXJuIGNsYW1wKDAsIHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5saW5lQ291bnQgLSAxLCBsaW5lKTtcbn1cbmNvbnN0IGdldENvZGVMaW5lRWxlbWVudHMgPSAoKCkgPT4ge1xuICAgIGxldCBlbGVtZW50cztcbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgICBpZiAoIWVsZW1lbnRzKSB7XG4gICAgICAgICAgICBlbGVtZW50cyA9IFt7IGVsZW1lbnQ6IGRvY3VtZW50LmJvZHksIGxpbmU6IDAgfV07XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZShjb2RlTGluZUNsYXNzKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGxpbmUgPSArZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtbGluZScpO1xuICAgICAgICAgICAgICAgIGlmIChpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGVsZW1lbnQudGFnTmFtZSA9PT0gJ0NPREUnICYmIGVsZW1lbnQucGFyZW50RWxlbWVudCAmJiBlbGVtZW50LnBhcmVudEVsZW1lbnQudGFnTmFtZSA9PT0gJ1BSRScpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRmVuY2hlZCBjb2RlIGJsb2NrcyBhcmUgYSBzcGVjaWFsIGNhc2Ugc2luY2UgdGhlIGBjb2RlLWxpbmVgIGNhbiBvbmx5IGJlIG1hcmtlZCBvblxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgYDxjb2RlPmAgZWxlbWVudCBhbmQgbm90IHRoZSBwYXJlbnQgYDxwcmU+YCBlbGVtZW50LlxuICAgICAgICAgICAgICAgICAgICBlbGVtZW50cy5wdXNoKHsgZWxlbWVudDogZWxlbWVudC5wYXJlbnRFbGVtZW50LCBsaW5lIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZWxlbWVudHMucHVzaCh7IGVsZW1lbnQ6IGVsZW1lbnQsIGxpbmUgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbGVtZW50cztcbiAgICB9O1xufSkoKTtcbi8qKlxuICogRmluZCB0aGUgaHRtbCBlbGVtZW50cyB0aGF0IG1hcCB0byBhIHNwZWNpZmljIHRhcmdldCBsaW5lIGluIHRoZSBlZGl0b3IuXG4gKlxuICogSWYgYW4gZXhhY3QgbWF0Y2gsIHJldHVybnMgYSBzaW5nbGUgZWxlbWVudC4gSWYgdGhlIGxpbmUgaXMgYmV0d2VlbiBlbGVtZW50cyxcbiAqIHJldHVybnMgdGhlIGVsZW1lbnQgcHJpb3IgdG8gYW5kIHRoZSBlbGVtZW50IGFmdGVyIHRoZSBnaXZlbiBsaW5lLlxuICovXG5mdW5jdGlvbiBnZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUodGFyZ2V0TGluZSkge1xuICAgIGNvbnN0IGxpbmVOdW1iZXIgPSBNYXRoLmZsb29yKHRhcmdldExpbmUpO1xuICAgIGNvbnN0IGxpbmVzID0gZ2V0Q29kZUxpbmVFbGVtZW50cygpO1xuICAgIGxldCBwcmV2aW91cyA9IGxpbmVzWzBdIHx8IG51bGw7XG4gICAgZm9yIChjb25zdCBlbnRyeSBvZiBsaW5lcykge1xuICAgICAgICBpZiAoZW50cnkubGluZSA9PT0gbGluZU51bWJlcikge1xuICAgICAgICAgICAgcmV0dXJuIHsgcHJldmlvdXM6IGVudHJ5LCBuZXh0OiB1bmRlZmluZWQgfTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChlbnRyeS5saW5lID4gbGluZU51bWJlcikge1xuICAgICAgICAgICAgcmV0dXJuIHsgcHJldmlvdXMsIG5leHQ6IGVudHJ5IH07XG4gICAgICAgIH1cbiAgICAgICAgcHJldmlvdXMgPSBlbnRyeTtcbiAgICB9XG4gICAgcmV0dXJuIHsgcHJldmlvdXMgfTtcbn1cbmV4cG9ydHMuZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lID0gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lO1xuLyoqXG4gKiBGaW5kIHRoZSBodG1sIGVsZW1lbnRzIHRoYXQgYXJlIGF0IGEgc3BlY2lmaWMgcGl4ZWwgb2Zmc2V0IG9uIHRoZSBwYWdlLlxuICovXG5mdW5jdGlvbiBnZXRMaW5lRWxlbWVudHNBdFBhZ2VPZmZzZXQob2Zmc2V0KSB7XG4gICAgY29uc3QgbGluZXMgPSBnZXRDb2RlTGluZUVsZW1lbnRzKCk7XG4gICAgY29uc3QgcG9zaXRpb24gPSBvZmZzZXQgLSB3aW5kb3cuc2Nyb2xsWTtcbiAgICBsZXQgbG8gPSAtMTtcbiAgICBsZXQgaGkgPSBsaW5lcy5sZW5ndGggLSAxO1xuICAgIHdoaWxlIChsbyArIDEgPCBoaSkge1xuICAgICAgICBjb25zdCBtaWQgPSBNYXRoLmZsb29yKChsbyArIGhpKSAvIDIpO1xuICAgICAgICBjb25zdCBib3VuZHMgPSBnZXRFbGVtZW50Qm91bmRzKGxpbmVzW21pZF0pO1xuICAgICAgICBpZiAoYm91bmRzLnRvcCArIGJvdW5kcy5oZWlnaHQgPj0gcG9zaXRpb24pIHtcbiAgICAgICAgICAgIGhpID0gbWlkO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbG8gPSBtaWQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgY29uc3QgaGlFbGVtZW50ID0gbGluZXNbaGldO1xuICAgIGNvbnN0IGhpQm91bmRzID0gZ2V0RWxlbWVudEJvdW5kcyhoaUVsZW1lbnQpO1xuICAgIGlmIChoaSA+PSAxICYmIGhpQm91bmRzLnRvcCA+IHBvc2l0aW9uKSB7XG4gICAgICAgIGNvbnN0IGxvRWxlbWVudCA9IGxpbmVzW2xvXTtcbiAgICAgICAgcmV0dXJuIHsgcHJldmlvdXM6IGxvRWxlbWVudCwgbmV4dDogaGlFbGVtZW50IH07XG4gICAgfVxuICAgIGlmIChoaSA+IDEgJiYgaGkgPCBsaW5lcy5sZW5ndGggJiYgaGlCb3VuZHMudG9wICsgaGlCb3VuZHMuaGVpZ2h0ID4gcG9zaXRpb24pIHtcbiAgICAgICAgcmV0dXJuIHsgcHJldmlvdXM6IGhpRWxlbWVudCwgbmV4dDogbGluZXNbaGkgKyAxXSB9O1xuICAgIH1cbiAgICByZXR1cm4geyBwcmV2aW91czogaGlFbGVtZW50IH07XG59XG5leHBvcnRzLmdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldCA9IGdldExpbmVFbGVtZW50c0F0UGFnZU9mZnNldDtcbmZ1bmN0aW9uIGdldEVsZW1lbnRCb3VuZHMoeyBlbGVtZW50IH0pIHtcbiAgICBjb25zdCBteUJvdW5kcyA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgLy8gU29tZSBjb2RlIGxpbmUgZWxlbWVudHMgbWF5IGNvbnRhaW4gb3RoZXIgY29kZSBsaW5lIGVsZW1lbnRzLlxuICAgIC8vIEluIHRob3NlIGNhc2VzLCBvbmx5IHRha2UgdGhlIGhlaWdodCB1cCB0byB0aGF0IGNoaWxkLlxuICAgIGNvbnN0IGNvZGVMaW5lQ2hpbGQgPSBlbGVtZW50LnF1ZXJ5U2VsZWN0b3IoYC4ke2NvZGVMaW5lQ2xhc3N9YCk7XG4gICAgaWYgKGNvZGVMaW5lQ2hpbGQpIHtcbiAgICAgICAgY29uc3QgY2hpbGRCb3VuZHMgPSBjb2RlTGluZUNoaWxkLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCBoZWlnaHQgPSBNYXRoLm1heCgxLCAoY2hpbGRCb3VuZHMudG9wIC0gbXlCb3VuZHMudG9wKSk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0b3A6IG15Qm91bmRzLnRvcCxcbiAgICAgICAgICAgIGhlaWdodDogaGVpZ2h0XG4gICAgICAgIH07XG4gICAgfVxuICAgIHJldHVybiBteUJvdW5kcztcbn1cbi8qKlxuICogQXR0ZW1wdCB0byByZXZlYWwgdGhlIGVsZW1lbnQgZm9yIGEgc291cmNlIGxpbmUgaW4gdGhlIGVkaXRvci5cbiAqL1xuZnVuY3Rpb24gc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGxpbmUpIHtcbiAgICBpZiAoIXNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChsaW5lIDw9IDApIHtcbiAgICAgICAgd2luZG93LnNjcm9sbCh3aW5kb3cuc2Nyb2xsWCwgMCk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgeyBwcmV2aW91cywgbmV4dCB9ID0gZ2V0RWxlbWVudHNGb3JTb3VyY2VMaW5lKGxpbmUpO1xuICAgIGlmICghcHJldmlvdXMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgc2Nyb2xsVG8gPSAwO1xuICAgIGNvbnN0IHJlY3QgPSBnZXRFbGVtZW50Qm91bmRzKHByZXZpb3VzKTtcbiAgICBjb25zdCBwcmV2aW91c1RvcCA9IHJlY3QudG9wO1xuICAgIGlmIChuZXh0ICYmIG5leHQubGluZSAhPT0gcHJldmlvdXMubGluZSkge1xuICAgICAgICAvLyBCZXR3ZWVuIHR3byBlbGVtZW50cy4gR28gdG8gcGVyY2VudGFnZSBvZmZzZXQgYmV0d2VlbiB0aGVtLlxuICAgICAgICBjb25zdCBiZXR3ZWVuUHJvZ3Jlc3MgPSAobGluZSAtIHByZXZpb3VzLmxpbmUpIC8gKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuICAgICAgICBjb25zdCBlbGVtZW50T2Zmc2V0ID0gbmV4dC5lbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCAtIHByZXZpb3VzVG9wO1xuICAgICAgICBzY3JvbGxUbyA9IHByZXZpb3VzVG9wICsgYmV0d2VlblByb2dyZXNzICogZWxlbWVudE9mZnNldDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IHByb2dyZXNzSW5FbGVtZW50ID0gbGluZSAtIE1hdGguZmxvb3IobGluZSk7XG4gICAgICAgIHNjcm9sbFRvID0gcHJldmlvdXNUb3AgKyAocmVjdC5oZWlnaHQgKiBwcm9ncmVzc0luRWxlbWVudCk7XG4gICAgfVxuICAgIHdpbmRvdy5zY3JvbGwod2luZG93LnNjcm9sbFgsIE1hdGgubWF4KDEsIHdpbmRvdy5zY3JvbGxZICsgc2Nyb2xsVG8pKTtcbn1cbmV4cG9ydHMuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lID0gc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lO1xuZnVuY3Rpb24gZ2V0RWRpdG9yTGluZU51bWJlckZvclBhZ2VPZmZzZXQob2Zmc2V0KSB7XG4gICAgY29uc3QgeyBwcmV2aW91cywgbmV4dCB9ID0gZ2V0TGluZUVsZW1lbnRzQXRQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHByZXZpb3VzKSB7XG4gICAgICAgIGNvbnN0IHByZXZpb3VzQm91bmRzID0gZ2V0RWxlbWVudEJvdW5kcyhwcmV2aW91cyk7XG4gICAgICAgIGNvbnN0IG9mZnNldEZyb21QcmV2aW91cyA9IChvZmZzZXQgLSB3aW5kb3cuc2Nyb2xsWSAtIHByZXZpb3VzQm91bmRzLnRvcCk7XG4gICAgICAgIGlmIChuZXh0KSB7XG4gICAgICAgICAgICBjb25zdCBwcm9ncmVzc0JldHdlZW5FbGVtZW50cyA9IG9mZnNldEZyb21QcmV2aW91cyAvIChnZXRFbGVtZW50Qm91bmRzKG5leHQpLnRvcCAtIHByZXZpb3VzQm91bmRzLnRvcCk7XG4gICAgICAgICAgICBjb25zdCBsaW5lID0gcHJldmlvdXMubGluZSArIHByb2dyZXNzQmV0d2VlbkVsZW1lbnRzICogKG5leHQubGluZSAtIHByZXZpb3VzLmxpbmUpO1xuICAgICAgICAgICAgcmV0dXJuIGNsYW1wTGluZShsaW5lKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHByb2dyZXNzV2l0aGluRWxlbWVudCA9IG9mZnNldEZyb21QcmV2aW91cyAvIChwcmV2aW91c0JvdW5kcy5oZWlnaHQpO1xuICAgICAgICAgICAgY29uc3QgbGluZSA9IHByZXZpb3VzLmxpbmUgKyBwcm9ncmVzc1dpdGhpbkVsZW1lbnQ7XG4gICAgICAgICAgICByZXR1cm4gY2xhbXBMaW5lKGxpbmUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufVxuZXhwb3J0cy5nZXRFZGl0b3JMaW5lTnVtYmVyRm9yUGFnZU9mZnNldCA9IGdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0O1xuLyoqXG4gKiBUcnkgdG8gZmluZCB0aGUgaHRtbCBlbGVtZW50IGJ5IHVzaW5nIGEgZnJhZ21lbnQgaWRcbiAqL1xuZnVuY3Rpb24gZ2V0TGluZUVsZW1lbnRGb3JGcmFnbWVudChmcmFnbWVudCkge1xuICAgIHJldHVybiBnZXRDb2RlTGluZUVsZW1lbnRzKCkuZmluZCgoZWxlbWVudCkgPT4ge1xuICAgICAgICByZXR1cm4gZWxlbWVudC5lbGVtZW50LmlkID09PSBmcmFnbWVudDtcbiAgICB9KTtcbn1cbmV4cG9ydHMuZ2V0TGluZUVsZW1lbnRGb3JGcmFnbWVudCA9IGdldExpbmVFbGVtZW50Rm9yRnJhZ21lbnQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3QgYWN0aXZlTGluZU1hcmtlcl8xID0gcmVxdWlyZShcIi4vYWN0aXZlTGluZU1hcmtlclwiKTtcbmNvbnN0IGV2ZW50c18xID0gcmVxdWlyZShcIi4vZXZlbnRzXCIpO1xuY29uc3QgbWVzc2FnaW5nXzEgPSByZXF1aXJlKFwiLi9tZXNzYWdpbmdcIik7XG5jb25zdCBzY3JvbGxfc3luY18xID0gcmVxdWlyZShcIi4vc2Nyb2xsLXN5bmNcIik7XG5jb25zdCBzZXR0aW5nc18xID0gcmVxdWlyZShcIi4vc2V0dGluZ3NcIik7XG5jb25zdCB0aHJvdHRsZSA9IHJlcXVpcmUoXCJsb2Rhc2gudGhyb3R0bGVcIik7XG5sZXQgc2Nyb2xsRGlzYWJsZWQgPSB0cnVlO1xuY29uc3QgbWFya2VyID0gbmV3IGFjdGl2ZUxpbmVNYXJrZXJfMS5BY3RpdmVMaW5lTWFya2VyKCk7XG5jb25zdCBzZXR0aW5ncyA9IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKTtcbmNvbnN0IHZzY29kZSA9IGFjcXVpcmVWc0NvZGVBcGkoKTtcbi8vIFNldCBWUyBDb2RlIHN0YXRlXG5sZXQgc3RhdGUgPSBzZXR0aW5nc18xLmdldERhdGEoJ2RhdGEtc3RhdGUnKTtcbnZzY29kZS5zZXRTdGF0ZShzdGF0ZSk7XG5jb25zdCBtZXNzYWdpbmcgPSBtZXNzYWdpbmdfMS5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUodnNjb2RlKTtcbndpbmRvdy5jc3BBbGVydGVyLnNldFBvc3RlcihtZXNzYWdpbmcpO1xud2luZG93LnN0eWxlTG9hZGluZ01vbml0b3Iuc2V0UG9zdGVyKG1lc3NhZ2luZyk7XG53aW5kb3cub25sb2FkID0gKCkgPT4ge1xuICAgIHVwZGF0ZUltYWdlU2l6ZXMoKTtcbn07XG5ldmVudHNfMS5vbmNlRG9jdW1lbnRMb2FkZWQoKCkgPT4ge1xuICAgIGlmIChzZXR0aW5ncy5zY3JvbGxQcmV2aWV3V2l0aEVkaXRvcikge1xuICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIC8vIFRyeSB0byBzY3JvbGwgdG8gZnJhZ21lbnQgaWYgYXZhaWxhYmxlXG4gICAgICAgICAgICBpZiAoc3RhdGUuZnJhZ21lbnQpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlbGVtZW50ID0gc2Nyb2xsX3N5bmNfMS5nZXRMaW5lRWxlbWVudEZvckZyYWdtZW50KHN0YXRlLmZyYWdtZW50KTtcbiAgICAgICAgICAgICAgICBpZiAoZWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGVsZW1lbnQubGluZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc3QgaW5pdGlhbExpbmUgPSArc2V0dGluZ3MubGluZTtcbiAgICAgICAgICAgICAgICBpZiAoIWlzTmFOKGluaXRpYWxMaW5lKSkge1xuICAgICAgICAgICAgICAgICAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHNjcm9sbF9zeW5jXzEuc2Nyb2xsVG9SZXZlYWxTb3VyY2VMaW5lKGluaXRpYWxMaW5lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIDApO1xuICAgIH1cbn0pO1xuY29uc3Qgb25VcGRhdGVWaWV3ID0gKCgpID0+IHtcbiAgICBjb25zdCBkb1Njcm9sbCA9IHRocm90dGxlKChsaW5lKSA9PiB7XG4gICAgICAgIHNjcm9sbERpc2FibGVkID0gdHJ1ZTtcbiAgICAgICAgc2Nyb2xsX3N5bmNfMS5zY3JvbGxUb1JldmVhbFNvdXJjZUxpbmUobGluZSk7XG4gICAgfSwgNTApO1xuICAgIHJldHVybiAobGluZSwgc2V0dGluZ3MpID0+IHtcbiAgICAgICAgaWYgKCFpc05hTihsaW5lKSkge1xuICAgICAgICAgICAgc2V0dGluZ3MubGluZSA9IGxpbmU7XG4gICAgICAgICAgICBkb1Njcm9sbChsaW5lKTtcbiAgICAgICAgfVxuICAgIH07XG59KSgpO1xubGV0IHVwZGF0ZUltYWdlU2l6ZXMgPSB0aHJvdHRsZSgoKSA9PiB7XG4gICAgY29uc3QgaW1hZ2VJbmZvID0gW107XG4gICAgbGV0IGltYWdlcyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbWcnKTtcbiAgICBpZiAoaW1hZ2VzKSB7XG4gICAgICAgIGxldCBpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgaW1hZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCBpbWcgPSBpbWFnZXNbaV07XG4gICAgICAgICAgICBpZiAoaW1nLmNsYXNzTGlzdC5jb250YWlucygnbG9hZGluZycpKSB7XG4gICAgICAgICAgICAgICAgaW1nLmNsYXNzTGlzdC5yZW1vdmUoJ2xvYWRpbmcnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGltYWdlSW5mby5wdXNoKHtcbiAgICAgICAgICAgICAgICBpZDogaW1nLmlkLFxuICAgICAgICAgICAgICAgIGhlaWdodDogaW1nLmhlaWdodCxcbiAgICAgICAgICAgICAgICB3aWR0aDogaW1nLndpZHRoXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ2NhY2hlSW1hZ2VTaXplcycsIGltYWdlSW5mbyk7XG4gICAgfVxufSwgNTApO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsICgpID0+IHtcbiAgICBzY3JvbGxEaXNhYmxlZCA9IHRydWU7XG4gICAgdXBkYXRlSW1hZ2VTaXplcygpO1xufSwgdHJ1ZSk7XG53aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsIGV2ZW50ID0+IHtcbiAgICBpZiAoZXZlbnQuZGF0YS5zb3VyY2UgIT09IHNldHRpbmdzLnNvdXJjZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHN3aXRjaCAoZXZlbnQuZGF0YS50eXBlKSB7XG4gICAgICAgIGNhc2UgJ29uRGlkQ2hhbmdlVGV4dEVkaXRvclNlbGVjdGlvbic6XG4gICAgICAgICAgICBtYXJrZXIub25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGV2ZW50LmRhdGEubGluZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAndXBkYXRlVmlldyc6XG4gICAgICAgICAgICBvblVwZGF0ZVZpZXcoZXZlbnQuZGF0YS5saW5lLCBzZXR0aW5ncyk7XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG59LCBmYWxzZSk7XG5kb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIGV2ZW50ID0+IHtcbiAgICBpZiAoIXNldHRpbmdzLmRvdWJsZUNsaWNrVG9Td2l0Y2hUb0VkaXRvcikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIElnbm9yZSBjbGlja3Mgb24gbGlua3NcbiAgICBmb3IgKGxldCBub2RlID0gZXZlbnQudGFyZ2V0OyBub2RlOyBub2RlID0gbm9kZS5wYXJlbnROb2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgPT09ICdBJykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IG9mZnNldCA9IGV2ZW50LnBhZ2VZO1xuICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KG9mZnNldCk7XG4gICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgbWVzc2FnaW5nLnBvc3RNZXNzYWdlKCdkaWRDbGljaycsIHsgbGluZTogTWF0aC5mbG9vcihsaW5lKSB9KTtcbiAgICB9XG59KTtcbmNvbnN0IHBhc3NUaHJvdWdoTGlua1NjaGVtZXMgPSBbJ2h0dHA6JywgJ2h0dHBzOicsICdtYWlsdG86JywgJ3ZzY29kZTonLCAndnNjb2RlLWluc2lkZXJzOiddO1xuZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCBldmVudCA9PiB7XG4gICAgaWYgKCFldmVudCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBub2RlID0gZXZlbnQudGFyZ2V0O1xuICAgIHdoaWxlIChub2RlKSB7XG4gICAgICAgIGlmIChub2RlLnRhZ05hbWUgJiYgbm9kZS50YWdOYW1lID09PSAnQScgJiYgbm9kZS5ocmVmKSB7XG4gICAgICAgICAgICBpZiAobm9kZS5nZXRBdHRyaWJ1dGUoJ2hyZWYnKS5zdGFydHNXaXRoKCcjJykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBQYXNzIHRocm91Z2gga25vd24gc2NoZW1lc1xuICAgICAgICAgICAgaWYgKHBhc3NUaHJvdWdoTGlua1NjaGVtZXMuc29tZShzY2hlbWUgPT4gbm9kZS5ocmVmLnN0YXJ0c1dpdGgoc2NoZW1lKSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBocmVmVGV4dCA9IG5vZGUuZ2V0QXR0cmlidXRlKCdkYXRhLWhyZWYnKSB8fCBub2RlLmdldEF0dHJpYnV0ZSgnaHJlZicpO1xuICAgICAgICAgICAgLy8gSWYgb3JpZ2luYWwgbGluayBkb2Vzbid0IGxvb2sgbGlrZSBhIHVybCwgZGVsZWdhdGUgYmFjayB0byBWUyBDb2RlIHRvIHJlc29sdmVcbiAgICAgICAgICAgIGlmICghL15bYS16XFwtXSs6L2kudGVzdChocmVmVGV4dCkpIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdpbmcucG9zdE1lc3NhZ2UoJ29wZW5MaW5rJywgeyBocmVmOiBocmVmVGV4dCB9KTtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBub2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgIH1cbn0sIHRydWUpO1xud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRocm90dGxlKCgpID0+IHtcbiAgICBpZiAoc2Nyb2xsRGlzYWJsZWQpIHtcbiAgICAgICAgc2Nyb2xsRGlzYWJsZWQgPSBmYWxzZTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IGxpbmUgPSBzY3JvbGxfc3luY18xLmdldEVkaXRvckxpbmVOdW1iZXJGb3JQYWdlT2Zmc2V0KHdpbmRvdy5zY3JvbGxZKTtcbiAgICAgICAgaWYgKHR5cGVvZiBsaW5lID09PSAnbnVtYmVyJyAmJiAhaXNOYU4obGluZSkpIHtcbiAgICAgICAgICAgIG1lc3NhZ2luZy5wb3N0TWVzc2FnZSgncmV2ZWFsTGluZScsIHsgbGluZSB9KTtcbiAgICAgICAgICAgIHN0YXRlLmxpbmUgPSBsaW5lO1xuICAgICAgICAgICAgdnNjb2RlLnNldFN0YXRlKHN0YXRlKTtcbiAgICAgICAgfVxuICAgIH1cbn0sIDUwKSk7XG4iLCJcInVzZSBzdHJpY3RcIjtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwgeyB2YWx1ZTogdHJ1ZSB9KTtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuY29uc3Qgc2Nyb2xsX3N5bmNfMSA9IHJlcXVpcmUoXCIuL3Njcm9sbC1zeW5jXCIpO1xuY2xhc3MgQWN0aXZlTGluZU1hcmtlciB7XG4gICAgb25EaWRDaGFuZ2VUZXh0RWRpdG9yU2VsZWN0aW9uKGxpbmUpIHtcbiAgICAgICAgY29uc3QgeyBwcmV2aW91cyB9ID0gc2Nyb2xsX3N5bmNfMS5nZXRFbGVtZW50c0ZvclNvdXJjZUxpbmUobGluZSk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZShwcmV2aW91cyAmJiBwcmV2aW91cy5lbGVtZW50KTtcbiAgICB9XG4gICAgX3VwZGF0ZShiZWZvcmUpIHtcbiAgICAgICAgdGhpcy5fdW5tYXJrQWN0aXZlRWxlbWVudCh0aGlzLl9jdXJyZW50KTtcbiAgICAgICAgdGhpcy5fbWFya0FjdGl2ZUVsZW1lbnQoYmVmb3JlKTtcbiAgICAgICAgdGhpcy5fY3VycmVudCA9IGJlZm9yZTtcbiAgICB9XG4gICAgX3VubWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSA9IGVsZW1lbnQuY2xhc3NOYW1lLnJlcGxhY2UoL1xcYmNvZGUtYWN0aXZlLWxpbmVcXGIvZywgJycpO1xuICAgIH1cbiAgICBfbWFya0FjdGl2ZUVsZW1lbnQoZWxlbWVudCkge1xuICAgICAgICBpZiAoIWVsZW1lbnQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlbGVtZW50LmNsYXNzTmFtZSArPSAnIGNvZGUtYWN0aXZlLWxpbmUnO1xuICAgIH1cbn1cbmV4cG9ydHMuQWN0aXZlTGluZU1hcmtlciA9IEFjdGl2ZUxpbmVNYXJrZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuZnVuY3Rpb24gb25jZURvY3VtZW50TG9hZGVkKGYpIHtcbiAgICBpZiAoZG9jdW1lbnQucmVhZHlTdGF0ZSA9PT0gJ2xvYWRpbmcnIHx8IGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICd1bmluaXRpYWxpemVkJykge1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCdET01Db250ZW50TG9hZGVkJywgZik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBmKCk7XG4gICAgfVxufVxuZXhwb3J0cy5vbmNlRG9jdW1lbnRMb2FkZWQgPSBvbmNlRG9jdW1lbnRMb2FkZWQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcbi8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKiAgQ29weXJpZ2h0IChjKSBNaWNyb3NvZnQgQ29ycG9yYXRpb24uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4gKiAgTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBMaWNlbnNlLiBTZWUgTGljZW5zZS50eHQgaW4gdGhlIHByb2plY3Qgcm9vdCBmb3IgbGljZW5zZSBpbmZvcm1hdGlvbi5cbiAqLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7IHZhbHVlOiB0cnVlIH0pO1xuY29uc3Qgc2V0dGluZ3NfMSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzXCIpO1xuZXhwb3J0cy5jcmVhdGVQb3N0ZXJGb3JWc0NvZGUgPSAodnNjb2RlKSA9PiB7XG4gICAgcmV0dXJuIG5ldyBjbGFzcyB7XG4gICAgICAgIHBvc3RNZXNzYWdlKHR5cGUsIGJvZHkpIHtcbiAgICAgICAgICAgIHZzY29kZS5wb3N0TWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgdHlwZSxcbiAgICAgICAgICAgICAgICBzb3VyY2U6IHNldHRpbmdzXzEuZ2V0U2V0dGluZ3MoKS5zb3VyY2UsXG4gICAgICAgICAgICAgICAgYm9keVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9O1xufTtcbiIsIi8qKlxuICogbG9kYXNoIChDdXN0b20gQnVpbGQpIDxodHRwczovL2xvZGFzaC5jb20vPlxuICogQnVpbGQ6IGBsb2Rhc2ggbW9kdWxhcml6ZSBleHBvcnRzPVwibnBtXCIgLW8gLi9gXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9ycyA8aHR0cHM6Ly9qcXVlcnkub3JnLz5cbiAqIFJlbGVhc2VkIHVuZGVyIE1JVCBsaWNlbnNlIDxodHRwczovL2xvZGFzaC5jb20vbGljZW5zZT5cbiAqIEJhc2VkIG9uIFVuZGVyc2NvcmUuanMgMS44LjMgPGh0dHA6Ly91bmRlcnNjb3JlanMub3JnL0xJQ0VOU0U+XG4gKiBDb3B5cmlnaHQgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbiAqL1xuXG4vKiogVXNlZCBhcyB0aGUgYFR5cGVFcnJvcmAgbWVzc2FnZSBmb3IgXCJGdW5jdGlvbnNcIiBtZXRob2RzLiAqL1xudmFyIEZVTkNfRVJST1JfVEVYVCA9ICdFeHBlY3RlZCBhIGZ1bmN0aW9uJztcblxuLyoqIFVzZWQgYXMgcmVmZXJlbmNlcyBmb3IgdmFyaW91cyBgTnVtYmVyYCBjb25zdGFudHMuICovXG52YXIgTkFOID0gMCAvIDA7XG5cbi8qKiBgT2JqZWN0I3RvU3RyaW5nYCByZXN1bHQgcmVmZXJlbmNlcy4gKi9cbnZhciBzeW1ib2xUYWcgPSAnW29iamVjdCBTeW1ib2xdJztcblxuLyoqIFVzZWQgdG8gbWF0Y2ggbGVhZGluZyBhbmQgdHJhaWxpbmcgd2hpdGVzcGFjZS4gKi9cbnZhciByZVRyaW0gPSAvXlxccyt8XFxzKyQvZztcblxuLyoqIFVzZWQgdG8gZGV0ZWN0IGJhZCBzaWduZWQgaGV4YWRlY2ltYWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmFkSGV4ID0gL15bLStdMHhbMC05YS1mXSskL2k7XG5cbi8qKiBVc2VkIHRvIGRldGVjdCBiaW5hcnkgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzQmluYXJ5ID0gL14wYlswMV0rJC9pO1xuXG4vKiogVXNlZCB0byBkZXRlY3Qgb2N0YWwgc3RyaW5nIHZhbHVlcy4gKi9cbnZhciByZUlzT2N0YWwgPSAvXjBvWzAtN10rJC9pO1xuXG4vKiogQnVpbHQtaW4gbWV0aG9kIHJlZmVyZW5jZXMgd2l0aG91dCBhIGRlcGVuZGVuY3kgb24gYHJvb3RgLiAqL1xudmFyIGZyZWVQYXJzZUludCA9IHBhcnNlSW50O1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYGdsb2JhbGAgZnJvbSBOb2RlLmpzLiAqL1xudmFyIGZyZWVHbG9iYWwgPSB0eXBlb2YgZ2xvYmFsID09ICdvYmplY3QnICYmIGdsb2JhbCAmJiBnbG9iYWwuT2JqZWN0ID09PSBPYmplY3QgJiYgZ2xvYmFsO1xuXG4vKiogRGV0ZWN0IGZyZWUgdmFyaWFibGUgYHNlbGZgLiAqL1xudmFyIGZyZWVTZWxmID0gdHlwZW9mIHNlbGYgPT0gJ29iamVjdCcgJiYgc2VsZiAmJiBzZWxmLk9iamVjdCA9PT0gT2JqZWN0ICYmIHNlbGY7XG5cbi8qKiBVc2VkIGFzIGEgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb2JqZWN0LiAqL1xudmFyIHJvb3QgPSBmcmVlR2xvYmFsIHx8IGZyZWVTZWxmIHx8IEZ1bmN0aW9uKCdyZXR1cm4gdGhpcycpKCk7XG5cbi8qKiBVc2VkIGZvciBidWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcy4gKi9cbnZhciBvYmplY3RQcm90byA9IE9iamVjdC5wcm90b3R5cGU7XG5cbi8qKlxuICogVXNlZCB0byByZXNvbHZlIHRoZVxuICogW2B0b1N0cmluZ1RhZ2BdKGh0dHA6Ly9lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzcuMC8jc2VjLW9iamVjdC5wcm90b3R5cGUudG9zdHJpbmcpXG4gKiBvZiB2YWx1ZXMuXG4gKi9cbnZhciBvYmplY3RUb1N0cmluZyA9IG9iamVjdFByb3RvLnRvU3RyaW5nO1xuXG4vKiBCdWlsdC1pbiBtZXRob2QgcmVmZXJlbmNlcyBmb3IgdGhvc2Ugd2l0aCB0aGUgc2FtZSBuYW1lIGFzIG90aGVyIGBsb2Rhc2hgIG1ldGhvZHMuICovXG52YXIgbmF0aXZlTWF4ID0gTWF0aC5tYXgsXG4gICAgbmF0aXZlTWluID0gTWF0aC5taW47XG5cbi8qKlxuICogR2V0cyB0aGUgdGltZXN0YW1wIG9mIHRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRoYXQgaGF2ZSBlbGFwc2VkIHNpbmNlXG4gKiB0aGUgVW5peCBlcG9jaCAoMSBKYW51YXJ5IDE5NzAgMDA6MDA6MDAgVVRDKS5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDIuNC4wXG4gKiBAY2F0ZWdvcnkgRGF0ZVxuICogQHJldHVybnMge251bWJlcn0gUmV0dXJucyB0aGUgdGltZXN0YW1wLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmRlZmVyKGZ1bmN0aW9uKHN0YW1wKSB7XG4gKiAgIGNvbnNvbGUubG9nKF8ubm93KCkgLSBzdGFtcCk7XG4gKiB9LCBfLm5vdygpKTtcbiAqIC8vID0+IExvZ3MgdGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgaXQgdG9vayBmb3IgdGhlIGRlZmVycmVkIGludm9jYXRpb24uXG4gKi9cbnZhciBub3cgPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHJvb3QuRGF0ZS5ub3coKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlYm91bmNlZCBmdW5jdGlvbiB0aGF0IGRlbGF5cyBpbnZva2luZyBgZnVuY2AgdW50aWwgYWZ0ZXIgYHdhaXRgXG4gKiBtaWxsaXNlY29uZHMgaGF2ZSBlbGFwc2VkIHNpbmNlIHRoZSBsYXN0IHRpbWUgdGhlIGRlYm91bmNlZCBmdW5jdGlvbiB3YXNcbiAqIGludm9rZWQuIFRoZSBkZWJvdW5jZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgIG1ldGhvZCB0byBjYW5jZWxcbiAqIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvIGltbWVkaWF0ZWx5IGludm9rZSB0aGVtLlxuICogUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2Agc2hvdWxkIGJlIGludm9rZWQgb24gdGhlXG4gKiBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGAgdGltZW91dC4gVGhlIGBmdW5jYCBpcyBpbnZva2VkXG4gKiB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uLiBTdWJzZXF1ZW50XG4gKiBjYWxscyB0byB0aGUgZGVib3VuY2VkIGZ1bmN0aW9uIHJldHVybiB0aGUgcmVzdWx0IG9mIHRoZSBsYXN0IGBmdW5jYFxuICogaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIGRlYm91bmNlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy5kZWJvdW5jZWAgYW5kIGBfLnRocm90dGxlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGRlYm91bmNlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIGRlbGF5LlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9ZmFsc2VdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgbGVhZGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0LlxuICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLm1heFdhaXRdXG4gKiAgVGhlIG1heGltdW0gdGltZSBgZnVuY2AgaXMgYWxsb3dlZCB0byBiZSBkZWxheWVkIGJlZm9yZSBpdCdzIGludm9rZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IGRlYm91bmNlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgY29zdGx5IGNhbGN1bGF0aW9ucyB3aGlsZSB0aGUgd2luZG93IHNpemUgaXMgaW4gZmx1eC5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdyZXNpemUnLCBfLmRlYm91bmNlKGNhbGN1bGF0ZUxheW91dCwgMTUwKSk7XG4gKlxuICogLy8gSW52b2tlIGBzZW5kTWFpbGAgd2hlbiBjbGlja2VkLCBkZWJvdW5jaW5nIHN1YnNlcXVlbnQgY2FsbHMuXG4gKiBqUXVlcnkoZWxlbWVudCkub24oJ2NsaWNrJywgXy5kZWJvdW5jZShzZW5kTWFpbCwgMzAwLCB7XG4gKiAgICdsZWFkaW5nJzogdHJ1ZSxcbiAqICAgJ3RyYWlsaW5nJzogZmFsc2VcbiAqIH0pKTtcbiAqXG4gKiAvLyBFbnN1cmUgYGJhdGNoTG9nYCBpcyBpbnZva2VkIG9uY2UgYWZ0ZXIgMSBzZWNvbmQgb2YgZGVib3VuY2VkIGNhbGxzLlxuICogdmFyIGRlYm91bmNlZCA9IF8uZGVib3VuY2UoYmF0Y2hMb2csIDI1MCwgeyAnbWF4V2FpdCc6IDEwMDAgfSk7XG4gKiB2YXIgc291cmNlID0gbmV3IEV2ZW50U291cmNlKCcvc3RyZWFtJyk7XG4gKiBqUXVlcnkoc291cmNlKS5vbignbWVzc2FnZScsIGRlYm91bmNlZCk7XG4gKlxuICogLy8gQ2FuY2VsIHRoZSB0cmFpbGluZyBkZWJvdW5jZWQgaW52b2NhdGlvbi5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdwb3BzdGF0ZScsIGRlYm91bmNlZC5jYW5jZWwpO1xuICovXG5mdW5jdGlvbiBkZWJvdW5jZShmdW5jLCB3YWl0LCBvcHRpb25zKSB7XG4gIHZhciBsYXN0QXJncyxcbiAgICAgIGxhc3RUaGlzLFxuICAgICAgbWF4V2FpdCxcbiAgICAgIHJlc3VsdCxcbiAgICAgIHRpbWVySWQsXG4gICAgICBsYXN0Q2FsbFRpbWUsXG4gICAgICBsYXN0SW52b2tlVGltZSA9IDAsXG4gICAgICBsZWFkaW5nID0gZmFsc2UsXG4gICAgICBtYXhpbmcgPSBmYWxzZSxcbiAgICAgIHRyYWlsaW5nID0gdHJ1ZTtcblxuICBpZiAodHlwZW9mIGZ1bmMgIT0gJ2Z1bmN0aW9uJykge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoRlVOQ19FUlJPUl9URVhUKTtcbiAgfVxuICB3YWl0ID0gdG9OdW1iZXIod2FpdCkgfHwgMDtcbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICEhb3B0aW9ucy5sZWFkaW5nO1xuICAgIG1heGluZyA9ICdtYXhXYWl0JyBpbiBvcHRpb25zO1xuICAgIG1heFdhaXQgPSBtYXhpbmcgPyBuYXRpdmVNYXgodG9OdW1iZXIob3B0aW9ucy5tYXhXYWl0KSB8fCAwLCB3YWl0KSA6IG1heFdhaXQ7XG4gICAgdHJhaWxpbmcgPSAndHJhaWxpbmcnIGluIG9wdGlvbnMgPyAhIW9wdGlvbnMudHJhaWxpbmcgOiB0cmFpbGluZztcbiAgfVxuXG4gIGZ1bmN0aW9uIGludm9rZUZ1bmModGltZSkge1xuICAgIHZhciBhcmdzID0gbGFzdEFyZ3MsXG4gICAgICAgIHRoaXNBcmcgPSBsYXN0VGhpcztcblxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgbGFzdEludm9rZVRpbWUgPSB0aW1lO1xuICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkodGhpc0FyZywgYXJncyk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGxlYWRpbmdFZGdlKHRpbWUpIHtcbiAgICAvLyBSZXNldCBhbnkgYG1heFdhaXRgIHRpbWVyLlxuICAgIGxhc3RJbnZva2VUaW1lID0gdGltZTtcbiAgICAvLyBTdGFydCB0aGUgdGltZXIgZm9yIHRoZSB0cmFpbGluZyBlZGdlLlxuICAgIHRpbWVySWQgPSBzZXRUaW1lb3V0KHRpbWVyRXhwaXJlZCwgd2FpdCk7XG4gICAgLy8gSW52b2tlIHRoZSBsZWFkaW5nIGVkZ2UuXG4gICAgcmV0dXJuIGxlYWRpbmcgPyBpbnZva2VGdW5jKHRpbWUpIDogcmVzdWx0O1xuICB9XG5cbiAgZnVuY3Rpb24gcmVtYWluaW5nV2FpdCh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZSxcbiAgICAgICAgcmVzdWx0ID0gd2FpdCAtIHRpbWVTaW5jZUxhc3RDYWxsO1xuXG4gICAgcmV0dXJuIG1heGluZyA/IG5hdGl2ZU1pbihyZXN1bHQsIG1heFdhaXQgLSB0aW1lU2luY2VMYXN0SW52b2tlKSA6IHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNob3VsZEludm9rZSh0aW1lKSB7XG4gICAgdmFyIHRpbWVTaW5jZUxhc3RDYWxsID0gdGltZSAtIGxhc3RDYWxsVGltZSxcbiAgICAgICAgdGltZVNpbmNlTGFzdEludm9rZSA9IHRpbWUgLSBsYXN0SW52b2tlVGltZTtcblxuICAgIC8vIEVpdGhlciB0aGlzIGlzIHRoZSBmaXJzdCBjYWxsLCBhY3Rpdml0eSBoYXMgc3RvcHBlZCBhbmQgd2UncmUgYXQgdGhlXG4gICAgLy8gdHJhaWxpbmcgZWRnZSwgdGhlIHN5c3RlbSB0aW1lIGhhcyBnb25lIGJhY2t3YXJkcyBhbmQgd2UncmUgdHJlYXRpbmdcbiAgICAvLyBpdCBhcyB0aGUgdHJhaWxpbmcgZWRnZSwgb3Igd2UndmUgaGl0IHRoZSBgbWF4V2FpdGAgbGltaXQuXG4gICAgcmV0dXJuIChsYXN0Q2FsbFRpbWUgPT09IHVuZGVmaW5lZCB8fCAodGltZVNpbmNlTGFzdENhbGwgPj0gd2FpdCkgfHxcbiAgICAgICh0aW1lU2luY2VMYXN0Q2FsbCA8IDApIHx8IChtYXhpbmcgJiYgdGltZVNpbmNlTGFzdEludm9rZSA+PSBtYXhXYWl0KSk7XG4gIH1cblxuICBmdW5jdGlvbiB0aW1lckV4cGlyZWQoKSB7XG4gICAgdmFyIHRpbWUgPSBub3coKTtcbiAgICBpZiAoc2hvdWxkSW52b2tlKHRpbWUpKSB7XG4gICAgICByZXR1cm4gdHJhaWxpbmdFZGdlKHRpbWUpO1xuICAgIH1cbiAgICAvLyBSZXN0YXJ0IHRoZSB0aW1lci5cbiAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHJlbWFpbmluZ1dhaXQodGltZSkpO1xuICB9XG5cbiAgZnVuY3Rpb24gdHJhaWxpbmdFZGdlKHRpbWUpIHtcbiAgICB0aW1lcklkID0gdW5kZWZpbmVkO1xuXG4gICAgLy8gT25seSBpbnZva2UgaWYgd2UgaGF2ZSBgbGFzdEFyZ3NgIHdoaWNoIG1lYW5zIGBmdW5jYCBoYXMgYmVlblxuICAgIC8vIGRlYm91bmNlZCBhdCBsZWFzdCBvbmNlLlxuICAgIGlmICh0cmFpbGluZyAmJiBsYXN0QXJncykge1xuICAgICAgcmV0dXJuIGludm9rZUZ1bmModGltZSk7XG4gICAgfVxuICAgIGxhc3RBcmdzID0gbGFzdFRoaXMgPSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNhbmNlbCgpIHtcbiAgICBpZiAodGltZXJJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGltZXJJZCk7XG4gICAgfVxuICAgIGxhc3RJbnZva2VUaW1lID0gMDtcbiAgICBsYXN0QXJncyA9IGxhc3RDYWxsVGltZSA9IGxhc3RUaGlzID0gdGltZXJJZCA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGZsdXNoKCkge1xuICAgIHJldHVybiB0aW1lcklkID09PSB1bmRlZmluZWQgPyByZXN1bHQgOiB0cmFpbGluZ0VkZ2Uobm93KCkpO1xuICB9XG5cbiAgZnVuY3Rpb24gZGVib3VuY2VkKCkge1xuICAgIHZhciB0aW1lID0gbm93KCksXG4gICAgICAgIGlzSW52b2tpbmcgPSBzaG91bGRJbnZva2UodGltZSk7XG5cbiAgICBsYXN0QXJncyA9IGFyZ3VtZW50cztcbiAgICBsYXN0VGhpcyA9IHRoaXM7XG4gICAgbGFzdENhbGxUaW1lID0gdGltZTtcblxuICAgIGlmIChpc0ludm9raW5nKSB7XG4gICAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBsZWFkaW5nRWRnZShsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgICAgaWYgKG1heGluZykge1xuICAgICAgICAvLyBIYW5kbGUgaW52b2NhdGlvbnMgaW4gYSB0aWdodCBsb29wLlxuICAgICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgICAgICByZXR1cm4gaW52b2tlRnVuYyhsYXN0Q2FsbFRpbWUpO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAodGltZXJJZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aW1lcklkID0gc2V0VGltZW91dCh0aW1lckV4cGlyZWQsIHdhaXQpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG4gIGRlYm91bmNlZC5jYW5jZWwgPSBjYW5jZWw7XG4gIGRlYm91bmNlZC5mbHVzaCA9IGZsdXNoO1xuICByZXR1cm4gZGVib3VuY2VkO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSB0aHJvdHRsZWQgZnVuY3Rpb24gdGhhdCBvbmx5IGludm9rZXMgYGZ1bmNgIGF0IG1vc3Qgb25jZSBwZXJcbiAqIGV2ZXJ5IGB3YWl0YCBtaWxsaXNlY29uZHMuIFRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gY29tZXMgd2l0aCBhIGBjYW5jZWxgXG4gKiBtZXRob2QgdG8gY2FuY2VsIGRlbGF5ZWQgYGZ1bmNgIGludm9jYXRpb25zIGFuZCBhIGBmbHVzaGAgbWV0aG9kIHRvXG4gKiBpbW1lZGlhdGVseSBpbnZva2UgdGhlbS4gUHJvdmlkZSBgb3B0aW9uc2AgdG8gaW5kaWNhdGUgd2hldGhlciBgZnVuY2BcbiAqIHNob3VsZCBiZSBpbnZva2VkIG9uIHRoZSBsZWFkaW5nIGFuZC9vciB0cmFpbGluZyBlZGdlIG9mIHRoZSBgd2FpdGBcbiAqIHRpbWVvdXQuIFRoZSBgZnVuY2AgaXMgaW52b2tlZCB3aXRoIHRoZSBsYXN0IGFyZ3VtZW50cyBwcm92aWRlZCB0byB0aGVcbiAqIHRocm90dGxlZCBmdW5jdGlvbi4gU3Vic2VxdWVudCBjYWxscyB0byB0aGUgdGhyb3R0bGVkIGZ1bmN0aW9uIHJldHVybiB0aGVcbiAqIHJlc3VsdCBvZiB0aGUgbGFzdCBgZnVuY2AgaW52b2NhdGlvbi5cbiAqXG4gKiAqKk5vdGU6KiogSWYgYGxlYWRpbmdgIGFuZCBgdHJhaWxpbmdgIG9wdGlvbnMgYXJlIGB0cnVlYCwgYGZ1bmNgIGlzXG4gKiBpbnZva2VkIG9uIHRoZSB0cmFpbGluZyBlZGdlIG9mIHRoZSB0aW1lb3V0IG9ubHkgaWYgdGhlIHRocm90dGxlZCBmdW5jdGlvblxuICogaXMgaW52b2tlZCBtb3JlIHRoYW4gb25jZSBkdXJpbmcgdGhlIGB3YWl0YCB0aW1lb3V0LlxuICpcbiAqIElmIGB3YWl0YCBpcyBgMGAgYW5kIGBsZWFkaW5nYCBpcyBgZmFsc2VgLCBgZnVuY2AgaW52b2NhdGlvbiBpcyBkZWZlcnJlZFxuICogdW50aWwgdG8gdGhlIG5leHQgdGljaywgc2ltaWxhciB0byBgc2V0VGltZW91dGAgd2l0aCBhIHRpbWVvdXQgb2YgYDBgLlxuICpcbiAqIFNlZSBbRGF2aWQgQ29yYmFjaG8ncyBhcnRpY2xlXShodHRwczovL2Nzcy10cmlja3MuY29tL2RlYm91bmNpbmctdGhyb3R0bGluZy1leHBsYWluZWQtZXhhbXBsZXMvKVxuICogZm9yIGRldGFpbHMgb3ZlciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgXy50aHJvdHRsZWAgYW5kIGBfLmRlYm91bmNlYC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDAuMS4wXG4gKiBAY2F0ZWdvcnkgRnVuY3Rpb25cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIHRocm90dGxlLlxuICogQHBhcmFtIHtudW1iZXJ9IFt3YWl0PTBdIFRoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHRocm90dGxlIGludm9jYXRpb25zIHRvLlxuICogQHBhcmFtIHtPYmplY3R9IFtvcHRpb25zPXt9XSBUaGUgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmxlYWRpbmc9dHJ1ZV1cbiAqICBTcGVjaWZ5IGludm9raW5nIG9uIHRoZSBsZWFkaW5nIGVkZ2Ugb2YgdGhlIHRpbWVvdXQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLnRyYWlsaW5nPXRydWVdXG4gKiAgU3BlY2lmeSBpbnZva2luZyBvbiB0aGUgdHJhaWxpbmcgZWRnZSBvZiB0aGUgdGltZW91dC5cbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gUmV0dXJucyB0aGUgbmV3IHRocm90dGxlZCBmdW5jdGlvbi5cbiAqIEBleGFtcGxlXG4gKlxuICogLy8gQXZvaWQgZXhjZXNzaXZlbHkgdXBkYXRpbmcgdGhlIHBvc2l0aW9uIHdoaWxlIHNjcm9sbGluZy5cbiAqIGpRdWVyeSh3aW5kb3cpLm9uKCdzY3JvbGwnLCBfLnRocm90dGxlKHVwZGF0ZVBvc2l0aW9uLCAxMDApKTtcbiAqXG4gKiAvLyBJbnZva2UgYHJlbmV3VG9rZW5gIHdoZW4gdGhlIGNsaWNrIGV2ZW50IGlzIGZpcmVkLCBidXQgbm90IG1vcmUgdGhhbiBvbmNlIGV2ZXJ5IDUgbWludXRlcy5cbiAqIHZhciB0aHJvdHRsZWQgPSBfLnRocm90dGxlKHJlbmV3VG9rZW4sIDMwMDAwMCwgeyAndHJhaWxpbmcnOiBmYWxzZSB9KTtcbiAqIGpRdWVyeShlbGVtZW50KS5vbignY2xpY2snLCB0aHJvdHRsZWQpO1xuICpcbiAqIC8vIENhbmNlbCB0aGUgdHJhaWxpbmcgdGhyb3R0bGVkIGludm9jYXRpb24uXG4gKiBqUXVlcnkod2luZG93KS5vbigncG9wc3RhdGUnLCB0aHJvdHRsZWQuY2FuY2VsKTtcbiAqL1xuZnVuY3Rpb24gdGhyb3R0bGUoZnVuYywgd2FpdCwgb3B0aW9ucykge1xuICB2YXIgbGVhZGluZyA9IHRydWUsXG4gICAgICB0cmFpbGluZyA9IHRydWU7XG5cbiAgaWYgKHR5cGVvZiBmdW5jICE9ICdmdW5jdGlvbicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKEZVTkNfRVJST1JfVEVYVCk7XG4gIH1cbiAgaWYgKGlzT2JqZWN0KG9wdGlvbnMpKSB7XG4gICAgbGVhZGluZyA9ICdsZWFkaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLmxlYWRpbmcgOiBsZWFkaW5nO1xuICAgIHRyYWlsaW5nID0gJ3RyYWlsaW5nJyBpbiBvcHRpb25zID8gISFvcHRpb25zLnRyYWlsaW5nIDogdHJhaWxpbmc7XG4gIH1cbiAgcmV0dXJuIGRlYm91bmNlKGZ1bmMsIHdhaXQsIHtcbiAgICAnbGVhZGluZyc6IGxlYWRpbmcsXG4gICAgJ21heFdhaXQnOiB3YWl0LFxuICAgICd0cmFpbGluZyc6IHRyYWlsaW5nXG4gIH0pO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBgdmFsdWVgIGlzIHRoZVxuICogW2xhbmd1YWdlIHR5cGVdKGh0dHA6Ly93d3cuZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi83LjAvI3NlYy1lY21hc2NyaXB0LWxhbmd1YWdlLXR5cGVzKVxuICogb2YgYE9iamVjdGAuIChlLmcuIGFycmF5cywgZnVuY3Rpb25zLCBvYmplY3RzLCByZWdleGVzLCBgbmV3IE51bWJlcigwKWAsIGFuZCBgbmV3IFN0cmluZygnJylgKVxuICpcbiAqIEBzdGF0aWNcbiAqIEBtZW1iZXJPZiBfXG4gKiBAc2luY2UgMC4xLjBcbiAqIEBjYXRlZ29yeSBMYW5nXG4gKiBAcGFyYW0geyp9IHZhbHVlIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBSZXR1cm5zIGB0cnVlYCBpZiBgdmFsdWVgIGlzIGFuIG9iamVjdCwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0KHt9KTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0KFsxLCAyLCAzXSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdChfLm5vb3ApO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNPYmplY3QobnVsbCk7XG4gKiAvLyA9PiBmYWxzZVxuICovXG5mdW5jdGlvbiBpc09iamVjdCh2YWx1ZSkge1xuICB2YXIgdHlwZSA9IHR5cGVvZiB2YWx1ZTtcbiAgcmV0dXJuICEhdmFsdWUgJiYgKHR5cGUgPT0gJ29iamVjdCcgfHwgdHlwZSA9PSAnZnVuY3Rpb24nKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZS4gQSB2YWx1ZSBpcyBvYmplY3QtbGlrZSBpZiBpdCdzIG5vdCBgbnVsbGBcbiAqIGFuZCBoYXMgYSBgdHlwZW9mYCByZXN1bHQgb2YgXCJvYmplY3RcIi5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYHZhbHVlYCBpcyBvYmplY3QtbGlrZSwgZWxzZSBgZmFsc2VgLlxuICogQGV4YW1wbGVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZSh7fSk7XG4gKiAvLyA9PiB0cnVlXG4gKlxuICogXy5pc09iamVjdExpa2UoWzEsIDIsIDNdKTtcbiAqIC8vID0+IHRydWVcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShfLm5vb3ApO1xuICogLy8gPT4gZmFsc2VcbiAqXG4gKiBfLmlzT2JqZWN0TGlrZShudWxsKTtcbiAqIC8vID0+IGZhbHNlXG4gKi9cbmZ1bmN0aW9uIGlzT2JqZWN0TGlrZSh2YWx1ZSkge1xuICByZXR1cm4gISF2YWx1ZSAmJiB0eXBlb2YgdmFsdWUgPT0gJ29iamVjdCc7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGB2YWx1ZWAgaXMgY2xhc3NpZmllZCBhcyBhIGBTeW1ib2xgIHByaW1pdGl2ZSBvciBvYmplY3QuXG4gKlxuICogQHN0YXRpY1xuICogQG1lbWJlck9mIF9cbiAqIEBzaW5jZSA0LjAuMFxuICogQGNhdGVnb3J5IExhbmdcbiAqIEBwYXJhbSB7Kn0gdmFsdWUgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIGB2YWx1ZWAgaXMgYSBzeW1ib2wsIGVsc2UgYGZhbHNlYC5cbiAqIEBleGFtcGxlXG4gKlxuICogXy5pc1N5bWJvbChTeW1ib2wuaXRlcmF0b3IpO1xuICogLy8gPT4gdHJ1ZVxuICpcbiAqIF8uaXNTeW1ib2woJ2FiYycpO1xuICogLy8gPT4gZmFsc2VcbiAqL1xuZnVuY3Rpb24gaXNTeW1ib2wodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PSAnc3ltYm9sJyB8fFxuICAgIChpc09iamVjdExpa2UodmFsdWUpICYmIG9iamVjdFRvU3RyaW5nLmNhbGwodmFsdWUpID09IHN5bWJvbFRhZyk7XG59XG5cbi8qKlxuICogQ29udmVydHMgYHZhbHVlYCB0byBhIG51bWJlci5cbiAqXG4gKiBAc3RhdGljXG4gKiBAbWVtYmVyT2YgX1xuICogQHNpbmNlIDQuMC4wXG4gKiBAY2F0ZWdvcnkgTGFuZ1xuICogQHBhcmFtIHsqfSB2YWx1ZSBUaGUgdmFsdWUgdG8gcHJvY2Vzcy5cbiAqIEByZXR1cm5zIHtudW1iZXJ9IFJldHVybnMgdGhlIG51bWJlci5cbiAqIEBleGFtcGxlXG4gKlxuICogXy50b051bWJlcigzLjIpO1xuICogLy8gPT4gMy4yXG4gKlxuICogXy50b051bWJlcihOdW1iZXIuTUlOX1ZBTFVFKTtcbiAqIC8vID0+IDVlLTMyNFxuICpcbiAqIF8udG9OdW1iZXIoSW5maW5pdHkpO1xuICogLy8gPT4gSW5maW5pdHlcbiAqXG4gKiBfLnRvTnVtYmVyKCczLjInKTtcbiAqIC8vID0+IDMuMlxuICovXG5mdW5jdGlvbiB0b051bWJlcih2YWx1ZSkge1xuICBpZiAodHlwZW9mIHZhbHVlID09ICdudW1iZXInKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG4gIGlmIChpc1N5bWJvbCh2YWx1ZSkpIHtcbiAgICByZXR1cm4gTkFOO1xuICB9XG4gIGlmIChpc09iamVjdCh2YWx1ZSkpIHtcbiAgICB2YXIgb3RoZXIgPSB0eXBlb2YgdmFsdWUudmFsdWVPZiA9PSAnZnVuY3Rpb24nID8gdmFsdWUudmFsdWVPZigpIDogdmFsdWU7XG4gICAgdmFsdWUgPSBpc09iamVjdChvdGhlcikgPyAob3RoZXIgKyAnJykgOiBvdGhlcjtcbiAgfVxuICBpZiAodHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIHZhbHVlID09PSAwID8gdmFsdWUgOiArdmFsdWU7XG4gIH1cbiAgdmFsdWUgPSB2YWx1ZS5yZXBsYWNlKHJlVHJpbSwgJycpO1xuICB2YXIgaXNCaW5hcnkgPSByZUlzQmluYXJ5LnRlc3QodmFsdWUpO1xuICByZXR1cm4gKGlzQmluYXJ5IHx8IHJlSXNPY3RhbC50ZXN0KHZhbHVlKSlcbiAgICA/IGZyZWVQYXJzZUludCh2YWx1ZS5zbGljZSgyKSwgaXNCaW5hcnkgPyAyIDogOClcbiAgICA6IChyZUlzQmFkSGV4LnRlc3QodmFsdWUpID8gTkFOIDogK3ZhbHVlKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB0aHJvdHRsZTtcbiIsInZhciBnO1xuXG4vLyBUaGlzIHdvcmtzIGluIG5vbi1zdHJpY3QgbW9kZVxuZyA9IChmdW5jdGlvbigpIHtcblx0cmV0dXJuIHRoaXM7XG59KSgpO1xuXG50cnkge1xuXHQvLyBUaGlzIHdvcmtzIGlmIGV2YWwgaXMgYWxsb3dlZCAoc2VlIENTUClcblx0ZyA9IGcgfHwgbmV3IEZ1bmN0aW9uKFwicmV0dXJuIHRoaXNcIikoKTtcbn0gY2F0Y2ggKGUpIHtcblx0Ly8gVGhpcyB3b3JrcyBpZiB0aGUgd2luZG93IHJlZmVyZW5jZSBpcyBhdmFpbGFibGVcblx0aWYgKHR5cGVvZiB3aW5kb3cgPT09IFwib2JqZWN0XCIpIGcgPSB3aW5kb3c7XG59XG5cbi8vIGcgY2FuIHN0aWxsIGJlIHVuZGVmaW5lZCwgYnV0IG5vdGhpbmcgdG8gZG8gYWJvdXQgaXQuLi5cbi8vIFdlIHJldHVybiB1bmRlZmluZWQsIGluc3RlYWQgb2Ygbm90aGluZyBoZXJlLCBzbyBpdCdzXG4vLyBlYXNpZXIgdG8gaGFuZGxlIHRoaXMgY2FzZS4gaWYoIWdsb2JhbCkgeyAuLi59XG5cbm1vZHVsZS5leHBvcnRzID0gZztcbiJdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index c18fc454210..303bd99f702 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -345,7 +345,7 @@ "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "ts-loader": "^6.2.1", - "typescript": "^3.6.4", + "typescript": "^3.7.2", "vscode": "^1.1.10", "webpack": "^4.41.2", "webpack-cli": "^3.3.0" diff --git a/extensions/markdown-language-features/preview-src/scroll-sync.ts b/extensions/markdown-language-features/preview-src/scroll-sync.ts index 2d12fd2731a..e833862066e 100644 --- a/extensions/markdown-language-features/preview-src/scroll-sync.ts +++ b/extensions/markdown-language-features/preview-src/scroll-sync.ts @@ -5,6 +5,7 @@ import { getSettings } from './settings'; +const codeLineClass = 'code-line'; function clamp(min: number, max: number, value: number) { return Math.min(max, Math.max(min, value)); @@ -25,7 +26,7 @@ const getCodeLineElements = (() => { return () => { if (!elements) { elements = [{ element: document.body, line: 0 }]; - for (const element of document.getElementsByClassName('code-line')) { + for (const element of document.getElementsByClassName(codeLineClass)) { const line = +element.getAttribute('data-line')!; if (isNaN(line)) { continue; @@ -75,7 +76,7 @@ export function getLineElementsAtPageOffset(offset: number): { previous: CodeLin let hi = lines.length - 1; while (lo + 1 < hi) { const mid = Math.floor((lo + hi) / 2); - const bounds = lines[mid].element.getBoundingClientRect(); + const bounds = getElementBounds(lines[mid]); if (bounds.top + bounds.height >= position) { hi = mid; } @@ -84,7 +85,7 @@ export function getLineElementsAtPageOffset(offset: number): { previous: CodeLin } } const hiElement = lines[hi]; - const hiBounds = hiElement.element.getBoundingClientRect(); + const hiBounds = getElementBounds(hiElement); if (hi >= 1 && hiBounds.top > position) { const loElement = lines[lo]; return { previous: loElement, next: hiElement }; @@ -95,6 +96,24 @@ export function getLineElementsAtPageOffset(offset: number): { previous: CodeLin return { previous: hiElement }; } +function getElementBounds({ element }: CodeLineElement): { top: number, height: number } { + const myBounds = element.getBoundingClientRect(); + + // Some code line elements may contain other code line elements. + // In those cases, only take the height up to that child. + const codeLineChild = element.querySelector(`.${codeLineClass}`); + if (codeLineChild) { + const childBounds = codeLineChild.getBoundingClientRect(); + const height = Math.max(1, (childBounds.top - myBounds.top)); + return { + top: myBounds.top, + height: height + }; + } + + return myBounds; +} + /** * Attempt to reveal the element for a source line in the editor. */ @@ -113,7 +132,7 @@ export function scrollToRevealSourceLine(line: number) { return; } let scrollTo = 0; - const rect = previous.element.getBoundingClientRect(); + const rect = getElementBounds(previous); const previousTop = rect.top; if (next && next.line !== previous.line) { // Between two elements. Go to percentage offset between them. @@ -130,10 +149,10 @@ export function scrollToRevealSourceLine(line: number) { export function getEditorLineNumberForPageOffset(offset: number) { const { previous, next } = getLineElementsAtPageOffset(offset); if (previous) { - const previousBounds = previous.element.getBoundingClientRect(); + const previousBounds = getElementBounds(previous); const offsetFromPrevious = (offset - window.scrollY - previousBounds.top); if (next) { - const progressBetweenElements = offsetFromPrevious / (next.element.getBoundingClientRect().top - previousBounds.top); + const progressBetweenElements = offsetFromPrevious / (getElementBounds(next).top - previousBounds.top); const line = previous.line + progressBetweenElements * (next.line - previous.line); return clampLine(line); } else { diff --git a/extensions/markdown-language-features/src/features/preview.ts b/extensions/markdown-language-features/src/features/preview.ts index 0865b819b08..2fbf35d8b20 100644 --- a/extensions/markdown-language-features/src/features/preview.ts +++ b/extensions/markdown-language-features/src/features/preview.ts @@ -223,7 +223,7 @@ export class DynamicMarkdownPreview extends Disposable { this._register(vscode.window.onDidChangeActiveTextEditor(editor => { if (editor && isMarkdownFile(editor.document) && !this._locked) { - this.update(editor.document.uri); + this.update(editor.document.uri, false); } })); @@ -264,7 +264,6 @@ export class DynamicMarkdownPreview extends Disposable { this._onDisposeEmitter.fire(); this._onDisposeEmitter.dispose(); - this._onDidChangeViewStateEmitter.dispose(); this.editor.dispose(); super.dispose(); } diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index cf99e4dacff..956c4571523 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -4528,10 +4528,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.6.4: - version "3.6.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.4.tgz#b18752bb3792bc1a0281335f7f6ebf1bbfc5b91d" - integrity sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg== +typescript@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb" + integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ== uc.micro@^1.0.1: version "1.0.3" diff --git a/extensions/scss/cgmanifest.json b/extensions/scss/cgmanifest.json index 7d152d3d3f3..12247769ce2 100644 --- a/extensions/scss/cgmanifest.json +++ b/extensions/scss/cgmanifest.json @@ -6,12 +6,12 @@ "git": { "name": "atom/language-sass", "repositoryUrl": "https://github.com/atom/language-sass", - "commitHash": "d01d29191ab323fb3cf8bde9df0429f8e07902ff" + "commitHash": "f52ab12f7f9346cc2568129d8c4419bd3d506b47" } }, "license": "MIT", "description": "The file syntaxes/scss.json was derived from the Atom package https://github.com/atom/language-sass which was originally converted from the TextMate bundle https://github.com/alexsancho/SASS.tmbundle.", - "version": "0.62.0" + "version": "0.62.1" } ], "version": 1 diff --git a/extensions/scss/syntaxes/scss.tmLanguage.json b/extensions/scss/syntaxes/scss.tmLanguage.json index 5add08181f6..21ed870a5cc 100644 --- a/extensions/scss/syntaxes/scss.tmLanguage.json +++ b/extensions/scss/syntaxes/scss.tmLanguage.json @@ -4,13 +4,19 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/atom/language-sass/commit/d01d29191ab323fb3cf8bde9df0429f8e07902ff", + "version": "https://github.com/atom/language-sass/commit/f52ab12f7f9346cc2568129d8c4419bd3d506b47", "name": "SCSS", "scopeName": "source.css.scss", "patterns": [ { "include": "#variable_setting" }, + { + "include": "#at_rule_forward" + }, + { + "include": "#at_rule_use" + }, { "include": "#at_rule_include" }, @@ -239,6 +245,55 @@ } ] }, + "at_rule_forward": { + "begin": "\\s*((@)forward\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.at-rule.forward.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?=;)", + "name": "meta.at-rule.forward.scss", + "patterns": [ + { + "match": "\\b(as|hide|show)\\b", + "name": "keyword.control.operator" + }, + { + "match": "\\b([\\w-]+)(\\*)", + "captures": { + "1": { + "name": "entity.other.attribute-name.module.scss" + }, + "2": { + "name": "punctuation.definition.wildcard.scss" + } + } + }, + { + "match": "\\b[\\w-]+\\b", + "name": "entity.name.function.scss" + }, + { + "include": "#variable" + }, + { + "include": "#string_single" + }, + { + "include": "#string_double" + }, + { + "include": "#comment_line" + }, + { + "include": "#comment_block" + } + ] + }, "at_rule_function": { "patterns": [ { @@ -336,12 +391,18 @@ "at_rule_include": { "patterns": [ { - "begin": "(?<=@include)\\s+([\\w-]+)\\s*(\\()", + "begin": "(?<=@include)\\s+(?:([\\w-]+)\\s*(\\.))?([\\w-]+)\\s*(\\()", "beginCaptures": { "1": { - "name": "entity.name.function.scss" + "name": "variable.scss" }, "2": { + "name": "punctuation.access.module.scss" + }, + "3": { + "name": "entity.name.function.scss" + }, + "4": { "name": "punctuation.definition.parameters.begin.bracket.round.scss" } }, @@ -359,12 +420,18 @@ ] }, { - "match": "(?<=@include)\\s+([\\w-]+)", + "match": "(?<=@include)\\s+(?:([\\w-]+)\\s*(\\.))?([\\w-]+)", "captures": { "0": { "name": "meta.at-rule.include.scss" }, "1": { + "name": "variable.scss" + }, + "2": { + "name": "punctuation.access.module.scss" + }, + "3": { "name": "entity.name.function.scss" } } @@ -794,6 +861,64 @@ } ] }, + "at_rule_use": { + "begin": "\\s*((@)use\\b)\\s*", + "captures": { + "1": { + "name": "keyword.control.at-rule.use.scss" + }, + "2": { + "name": "punctuation.definition.keyword.scss" + } + }, + "end": "\\s*(?=;)", + "name": "meta.at-rule.use.scss", + "patterns": [ + { + "match": "\\b(as|with)\\b", + "name": "keyword.control.operator" + }, + { + "match": "\\b[\\w-]+\\b", + "name": "variable.scss" + }, + { + "match": "\\*", + "name": "variable.language.expanded-namespace.scss" + }, + { + "include": "#string_single" + }, + { + "include": "#string_double" + }, + { + "include": "#comment_line" + }, + { + "include": "#comment_block" + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.parameters.begin.bracket.round.scss" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.bracket.round.scss" + } + }, + "patterns": [ + { + "include": "#function_attributes" + } + ] + } + ] + }, "at_rule_warn": { "begin": "\\s*((@)(warn|debug|error)\\b)\\s*", "captures": { @@ -890,12 +1015,18 @@ "name": "keyword.other.default.scss" }, "constant_functions": { - "begin": "([\\w-]+)(\\()", + "begin": "(?:([\\w-]+)(\\.))?([\\w-]+)(\\()", "beginCaptures": { "1": { - "name": "support.function.misc.scss" + "name": "variable.scss" }, "2": { + "name": "punctuation.access.module.scss" + }, + "3": { + "name": "support.function.misc.scss" + }, + "4": { "name": "punctuation.section.function.scss" } }, @@ -1050,10 +1181,10 @@ "name": "variable.interpolation.scss", "patterns": [ { - "include": "#property_values" + "include": "#variable" }, { - "include": "#variable" + "include": "#property_values" } ] }, @@ -1118,10 +1249,10 @@ "include": "#map" }, { - "include": "#property_values" + "include": "#variable" }, { - "include": "#variable" + "include": "#property_values" } ] }, @@ -1326,7 +1457,7 @@ ] }, "selector_attribute": { - "match": "(?xi)\n(\\[)\n\\s*\n(\n (?:\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+?\n)\n(?:\n \\s*([~|^$*]?=)\\s*\n (?:\n (\n (?:\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n )\n |\n ((\")(.*?)(\"))\n |\n ((')(.*?)('))\n )\n)?\n\\s*\n(\\])", + "match": "(?xi)\n(\\[)\n\\s*\n(\n (?:\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.?\\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+?\n)\n(?:\n \\s*([~|^$*]?=)\\s*\n (?:\n (\n (?:\n [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.?\\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n )\n |\n ((\")(.*?)(\"))\n |\n ((')(.*?)('))\n )\n)?\n\\s*\n(\\])", "name": "meta.attribute-selector.scss", "captures": { "1": { @@ -1421,7 +1552,7 @@ } }, "selector_class": { - "match": "(?x)\n(\\.) # Valid class-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n | ; # - A semicolon\n)", + "match": "(?x)\n(\\.) # Valid class-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.?\\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,\\#)\\[:{>+~|] # - Another selector\n | \\.[^$] # - Class selector, negating module variable\n | /\\* # - A block comment\n | ; # - A semicolon\n)", "name": "entity.other.attribute-name.class.css", "captures": { "1": { @@ -1449,7 +1580,7 @@ "name": "entity.name.tag.custom.scss" }, "selector_id": { - "match": "(?x)\n(\\#) # Valid id-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", + "match": "(?x)\n(\\#) # Valid id-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.?\\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= $ # - End of the line\n | [\\s,\\#)\\[:{>+~|] # - Another selector\n | \\.[^$] # - Class selector, negating module variable\n | /\\* # - A block comment\n)", "name": "entity.other.attribute-name.id.css", "captures": { "1": { @@ -1473,7 +1604,7 @@ } }, "selector_placeholder": { - "match": "(?x)\n(%) # Valid placeholder-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= ; # - End of statement\n | $ # - End of the line\n | [\\s,.\\#)\\[:{>+~|] # - Another selector\n | /\\* # - A block comment\n)", + "match": "(?x)\n(%) # Valid placeholder-name\n(\n (?: [-a-zA-Z_0-9]|[^\\x00-\\x7F] # Valid identifier characters\n | \\\\(?:[0-9a-fA-F]{1,6}|.) # Escape sequence\n | \\#\\{ # Interpolation (escaped to avoid Coffeelint errors)\n | \\.\\$ # Possible start of interpolation module scope variable\n | \\$ # Possible start of interpolation variable\n | } # Possible end of interpolation\n )+\n) # Followed by either:\n(?= ; # - End of statement\n | $ # - End of the line\n | [\\s,\\#)\\[:{>+~|] # - Another selector\n | \\.[^$] # - Class selector, negating module variable\n | /\\* # - A block comment\n)", "name": "entity.other.attribute-name.placeholder.css", "captures": { "1": { @@ -1723,8 +1854,26 @@ ] }, "variables": { - "match": "(\\$|\\-\\-)[A-Za-z0-9_-]+\\b", - "name": "variable.scss" + "patterns": [ + { + "match": "\\b([\\w-]+)(\\.)(\\$[\\w-]+)\\b", + "captures": { + "1": { + "name": "variable.scss" + }, + "2": { + "name": "punctuation.access.module.scss" + }, + "3": { + "name": "variable.scss" + } + } + }, + { + "match": "(\\$|\\-\\-)[A-Za-z0-9_-]+\\b", + "name": "variable.scss" + } + ] } } } \ No newline at end of file diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index f0a326bb34d..1df39d31c90 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -252,6 +252,9 @@ ], "colors": { + "editor.background": "#000c18", + "editor.foreground": "#6688cc", + // Base // "foreground": "", "focusBorder": "#596F99", @@ -295,8 +298,6 @@ "scrollbarSlider.hoverBackground": "#3B3F5188", // Editor - "editor.background": "#000c18", - // "editor.foreground": "#6688cc", "editorWidget.background": "#262641", "editorCursor.foreground": "#ddbb88", "editorWhitespace.foreground": "#103050", diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index c9ea9573193..bb4187716ba 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -30,7 +30,7 @@ "format.placeOpenBraceOnNewLineForFunctions": "Defines whether an open brace is put onto a new line for functions or not.", "format.placeOpenBraceOnNewLineForControlBlocks": "Defines whether an open brace is put onto a new line for control blocks or not.", "format.semicolons": "Defines handling of optional semicolons. Requires using TypeScript 3.7 or newer in the workspace.", - "format.semicolons.ignore": "Don’t insert or remove any semicolons.", + "format.semicolons.ignore": "Don't insert or remove any semicolons.", "format.semicolons.insert": "Insert semicolons at statement ends.", "format.semicolons.remove": "Remove unnecessary semicolons.", "javascript.validate.enable": "Enable/disable JavaScript validation.", @@ -43,8 +43,8 @@ "typescript.selectTypeScriptVersion.title": "Select TypeScript Version...", "typescript.reportStyleChecksAsWarnings": "Report style checks as warnings.", "javascript.implicitProjectConfig.checkJs": "Enable/disable semantic checking of JavaScript files. Existing jsconfig.json or tsconfig.json files override this setting. Requires using TypeScript 2.3.1 or newer in the workspace.", - "typescript.npm": "Specifies the path to the NPM executable used for Automatic Type Acquisition. Requires using TypeScript 2.3.4 or newer in the workspace.", - "typescript.check.npmIsInstalled": "Check if NPM is installed for Automatic Type Acquisition.", + "typescript.npm": "Specifies the path to the npm executable used for Automatic Type Acquisition. Requires using TypeScript 2.3.4 or newer in the workspace.", + "typescript.check.npmIsInstalled": "Check if npm is installed for Automatic Type Acquisition.", "configuration.suggest.names": "Enable/disable including unique names from the file in JavaScript suggestions. Note that name suggestions are always disabled in JavaScript code that is semantically checked using `@ts-check` or `checkJs`.", "typescript.tsc.autoDetect": "Controls auto detection of tsc tasks.", "typescript.tsc.autoDetect.off": "Disable this feature.", diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index 3aafeb61e60..28e20135206 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -118,7 +118,11 @@ class BufferSynchronizer { } } - public beforeCommand(command: string) { + public reset(): void { + this._pending.clear(); + } + + public beforeCommand(command: string): void { if (command === 'updateOpen') { return; } @@ -150,7 +154,7 @@ class BufferSynchronizer { } private get supportsBatching(): boolean { - return this.client.apiVersion.gte(API.v340) && vscode.workspace.getConfiguration('typescript', null).get('useBatchedBufferSync', true); + return this.client.apiVersion.gte(API.v340); } private updatePending(resource: vscode.Uri, f: (pending: ResourceMap) => void): void { @@ -265,16 +269,15 @@ class GetErrRequest { files: ResourceMap, onDone: () => void ) { - const token = new vscode.CancellationTokenSource(); - return new GetErrRequest(client, files, token, onDone); + return new GetErrRequest(client, files, onDone); } private _done: boolean = false; + private readonly _token: vscode.CancellationTokenSource = new vscode.CancellationTokenSource(); private constructor( client: ITypeScriptServiceClient, public readonly files: ResourceMap, - private readonly _token: vscode.CancellationTokenSource, onDone: () => void ) { const args: Proto.GeterrRequestArgs = { @@ -282,7 +285,7 @@ class GetErrRequest { files: coalesce(Array.from(files.entries).map(entry => client.normalizedPath(entry.resource))) }; - client.executeAsync('geterr', args, _token.token) + client.executeAsync('geterr', args, this._token.token) .finally(() => { if (this._done) { return; @@ -394,7 +397,11 @@ export default class BufferSyncSupport extends Disposable { return vscode.Uri.file(filePath); } - public reOpenDocuments(): void { + public reset(): void { + this.pendingGetErr?.cancel(); + this.pendingDiagnostics.clear(); + this.synchronizer.reset(); + for (const buffer of this.syncedBuffers.allBuffers) { buffer.open(); } @@ -427,6 +434,7 @@ export default class BufferSyncSupport extends Disposable { return; } this.pendingDiagnostics.delete(resource); + this.pendingGetErr?.files.delete(resource); this.syncedBuffers.delete(resource); syncedBuffer.close(); this._onDelete.fire(resource); @@ -522,8 +530,10 @@ export default class BufferSyncSupport extends Disposable { if (this.pendingGetErr) { this.pendingGetErr.cancel(); - for (const file of this.pendingGetErr.files.entries) { - orderedFileSet.set(file.resource, undefined); + for (const { resource } of this.pendingGetErr.files.entries) { + if (this.syncedBuffers.get(resource)) { + orderedFileSet.set(resource, undefined); + } } } diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index cbcbc2e76a6..c0c1d6edc17 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -182,7 +182,7 @@ export default class TypeScriptServiceClientHost extends Disposable { private populateService(): void { this.fileConfigurationManager.reset(); - this.client.bufferSyncSupport.reOpenDocuments(); + this.client.bufferSyncSupport.reset(); this.client.bufferSyncSupport.requestAllDiagnostics(); // See https://github.com/Microsoft/TypeScript/issues/5530 diff --git a/extensions/typescript-language-features/src/utils/previewer.ts b/extensions/typescript-language-features/src/utils/previewer.ts index 2b2108ccd57..5ad230d662e 100644 --- a/extensions/typescript-language-features/src/utils/previewer.ts +++ b/extensions/typescript-language-features/src/utils/previewer.ts @@ -38,7 +38,10 @@ function getTagBodyText(tag: Proto.JSDocTagInfo): string | undefined { function getTagDocumentation(tag: Proto.JSDocTagInfo): string | undefined { switch (tag.name) { + case 'augments': + case 'extends': case 'param': + case 'template': const body = (tag.text || '').split(/^([\w\.]+)\s*-?\s*/); if (body && body.length === 3) { const param = body[1]; diff --git a/extensions/vscode-api-tests/src/extension.ts b/extensions/vscode-api-tests/src/extension.ts index a0aabfb09ec..7d345d9ae95 100644 --- a/extensions/vscode-api-tests/src/extension.ts +++ b/extensions/vscode-api-tests/src/extension.ts @@ -344,7 +344,7 @@ function enableProblems(context: vscode.ExtensionContext): void { } function updateDiagnostics(document: vscode.TextDocument, collection: vscode.DiagnosticCollection): void { - if (document && document.fileName === '/large.ts') { + if (document && document.fileName === '/sample-folder/large.ts') { collection.set(document.uri, [{ code: '', message: 'cannot assign twice to immutable variable `storeHouses`', @@ -366,9 +366,9 @@ function updateDiagnostics(document: vscode.TextDocument, collection: vscode.Dia } } -function enableSearch(_context: vscode.ExtensionContext, _memFs: MemFS): void { - // NOT YET SUPPORTED - //context.subscriptions.push(vscode.workspace.registerFileSearchProvider(SCHEME, memFs)); +function enableSearch(context: vscode.ExtensionContext, memFs: MemFS): void { + context.subscriptions.push(vscode.workspace.registerFileSearchProvider(SCHEME, memFs)); + context.subscriptions.push(vscode.workspace.registerTextSearchProvider(SCHEME, memFs)); } function enableTasks(): void { @@ -546,7 +546,7 @@ export class Directory implements vscode.FileStat { export type Entry = File | Directory; -export class MemFS implements vscode.FileSystemProvider, vscode.FileSearchProvider { +export class MemFS implements vscode.FileSystemProvider, vscode.FileSearchProvider, vscode.TextSearchProvider { root = new Directory(vscode.Uri.parse('memfs:/'), ''); @@ -796,16 +796,52 @@ export class MemFS implements vscode.FileSystemProvider, vscode.FileSearchProvid // --- search provider provideFileSearchResults(query: vscode.FileSearchQuery, _options: vscode.FileSearchOptions, _token: vscode.CancellationToken): vscode.ProviderResult { + return this._findFiles(query.pattern); + } + + private _findFiles(query: string | undefined): vscode.Uri[] { const files = this._getFiles(); const result: vscode.Uri[] = []; - const pattern = new RegExp(this._convertSimple2RegExpPattern(query.pattern)); + + const pattern = query ? new RegExp(this._convertSimple2RegExpPattern(query)) : null; for (const file of files) { - if (pattern.exec(file.name)) { + if (!pattern || pattern.exec(file.name)) { result.push(file.uri); } } return result; } + + private _textDecoder = new TextDecoder(); + + provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress, _token: vscode.CancellationToken) { + const result: vscode.TextSearchComplete = { limitHit: false }; + + const files = this._findFiles(options.includes[0]); + if (files) { + for (const file of files) { + const content = this._textDecoder.decode(this.readFile(file)); + + const lines = content.split('\n'); + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const index = line.indexOf(query.pattern); + if (index !== -1) { + progress.report({ + uri: file, + ranges: new vscode.Range(new vscode.Position(i, index), new vscode.Position(i, index + query.pattern.length)), + preview: { + text: line, + matches: new vscode.Range(new vscode.Position(0, index), new vscode.Position(0, index + query.pattern.length)) + } + }); + } + } + } + } + + return result; + } } diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts index 06728e206d9..7d552df04a8 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts @@ -23,6 +23,8 @@ suite('workspace-fs', () => { assert.equal(typeof stat.mtime, 'number'); assert.equal(typeof stat.ctime, 'number'); + assert.ok(stat.mtime > 0); + assert.ok(stat.ctime > 0); const entries = await vscode.workspace.fs.readDirectory(root); assert.ok(entries.length > 0); diff --git a/package.json b/package.json index 4f209cef0d2..51c1dc12a7a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "code-oss-dev", "version": "1.41.0", - "distro": "d9c8e16599fe4b979791417422d0575b417fbe61", + "distro": "be6ad88ea0214dfdb03b943bef28e7a5c9fc2e4b", "author": { "name": "Microsoft Corporation" }, @@ -36,7 +36,7 @@ "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.3", "iconv-lite": "0.5.0", - "jschardet": "1.6.0", + "jschardet": "2.1.1", "keytar": "^4.11.0", "native-is-elevated": "0.4.1", "native-keymap": "2.0.0", @@ -49,12 +49,12 @@ "v8-inspect-profiler": "^0.0.20", "vscode-minimist": "^1.2.1", "vscode-nsfw": "1.2.8", - "vscode-proxy-agent": "^0.5.1", + "vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.5.7", "vscode-sqlite3": "4.0.9", "vscode-textmate": "^4.3.0", - "xterm": "4.2.0", - "xterm-addon-search": "0.3.0", + "xterm": "4.3.0-beta17", + "xterm-addon-search": "0.4.0-beta4", "xterm-addon-web-links": "0.2.1", "yauzl": "^2.9.2", "yazl": "^2.4.3" @@ -65,6 +65,7 @@ "@types/chokidar": "2.1.3", "@types/cookie": "^0.3.3", "@types/graceful-fs": "4.1.2", + "@types/http-proxy-agent": "^2.0.1", "@types/iconv-lite": "0.0.1", "@types/keytar": "^4.4.0", "@types/mocha": "2.2.39", @@ -72,6 +73,7 @@ "@types/semver": "^5.5.0", "@types/sinon": "^1.16.36", "@types/webpack": "^4.4.10", + "@types/windows-foreground-love": "^0.3.0", "@types/winreg": "^1.2.30", "@types/yauzl": "^2.9.1", "@types/yazl": "^2.4.2", diff --git a/remote/package.json b/remote/package.json index 8daefb7feb5..ec299bfed0c 100644 --- a/remote/package.json +++ b/remote/package.json @@ -9,7 +9,7 @@ "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.3", "iconv-lite": "0.5.0", - "jschardet": "1.6.0", + "jschardet": "2.1.1", "native-watchdog": "1.2.0", "node-pty": "^0.10.0-beta2", "onigasm-umd": "^2.2.2", @@ -17,17 +17,17 @@ "spdlog": "^0.11.1", "vscode-minimist": "^1.2.1", "vscode-nsfw": "1.2.8", - "vscode-proxy-agent": "^0.5.1", + "vscode-proxy-agent": "^0.5.2", "vscode-ripgrep": "^1.5.7", "vscode-textmate": "^4.3.0", - "xterm": "4.2.0", - "xterm-addon-search": "0.3.0", + "xterm": "4.3.0-beta17", + "xterm-addon-search": "0.4.0-beta4", "xterm-addon-web-links": "0.2.1", "yauzl": "^2.9.2", "yazl": "^2.4.3" }, "optionalDependencies": { - "vscode-windows-ca-certs": "0.1.0", + "vscode-windows-ca-certs": "0.2.0", "vscode-windows-registry": "1.0.2" } } diff --git a/remote/web/package.json b/remote/web/package.json index 46207aac124..9889d010fab 100644 --- a/remote/web/package.json +++ b/remote/web/package.json @@ -5,8 +5,8 @@ "onigasm-umd": "^2.2.2", "semver-umd": "^5.5.3", "vscode-textmate": "^4.3.0", - "xterm": "4.2.0", - "xterm-addon-search": "0.3.0", + "xterm": "4.3.0-beta17", + "xterm-addon-search": "0.4.0-beta4", "xterm-addon-web-links": "0.2.1" } } diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock index 0a1c1d9859a..45a2296934f 100644 --- a/remote/web/yarn.lock +++ b/remote/web/yarn.lock @@ -31,17 +31,17 @@ vscode-textmate@^4.3.0: dependencies: oniguruma "^7.2.0" -xterm-addon-search@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0.tgz#fc6843bebab1873eff0c89e31f7b74bb3c4d8947" - integrity sha512-ZvRmkNBSz2dT00w0qJ3Hd5cwYoOfkVZpHou7Xxy1kO34wQglU/8Ec4DNTvU27sS9BUzEg8kUcTTru0DxhJXrTA== +xterm-addon-search@0.4.0-beta4: + version "0.4.0-beta4" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0-beta4.tgz#7762ea342c6b4f5e824d83466bd93793c9d7d779" + integrity sha512-TIbEBVhydGIxcyu/CfKJbD+BKHisMGbkAfaWlCPaWis2Xmw8yE7CKrCPn+lhZYl1MdjDVEmb8lQI6WetbC2OZA== xterm-addon-web-links@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2" integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ== -xterm@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0.tgz#b9980b2ae18c64ed31bcc95eace3bcecffebbbd9" - integrity sha512-oNfLqt+LmghLPOt5UcskP5Km1fXpTBHsTZ99nxJKY2N0MNFXBKIVXUcNNhHCa74JGZFMGhLT58A/UN3HcPXSfg== +xterm@4.3.0-beta17: + version "4.3.0-beta17" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.3.0-beta17.tgz#c038cc00cb5be33d2a5f083255c329d9ed186565" + integrity sha512-Lgz7vL12MBKJSgK/UXJF22Yw+uEXEE7YZDWfUD+/jbHAKN4geLQJ/Y/b3gxjLL020dnYZuayfKOr2KWdhKsmCA== diff --git a/remote/yarn.lock b/remote/yarn.lock index 7efd464929a..1aab9f6a9c0 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -217,10 +217,10 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -jschardet@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" - integrity sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ== +jschardet@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184" + integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q== jsonfile@^4.0.0: version "4.0.0" @@ -384,10 +384,10 @@ vscode-nsfw@1.2.8: lodash.isundefined "^3.0.1" nan "^2.10.0" -vscode-proxy-agent@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.1.tgz#7fd15e157c02176a0dca9f87840ad0991a62ca57" - integrity sha512-Nnkc7gBk9iAbbZURYZm3p/wvDvRVwDvdzEvDqF1Jh40p6przwQU/JTlV1XLrmd4cCwh6TOAWD81Z3cq+K7Xdmw== +vscode-proxy-agent@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.2.tgz#0c90d24d353957b841d741da7b2701e3f0a044c4" + integrity sha512-1cCNPxrWIrmUwS+1XGaXxkh3G1y7z2fpXl1sT74OZvELaryQWYb3NMxMLJJ4Q/CpPLEyuhp/bAN7nzHxxFcQ5Q== dependencies: debug "^3.1.0" http-proxy-agent "^2.1.0" @@ -406,10 +406,10 @@ vscode-textmate@^4.3.0: dependencies: oniguruma "^7.2.0" -vscode-windows-ca-certs@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.1.0.tgz#d58eeb40b536130918cfde2b01e6dc7e5c1bd757" - integrity sha512-ZfZbfJIE09Q0dwGqmqTj7kuAq4g6lul9WPJvo0DkKjln8/FL+dY3wUKIKbYwWQp4x56SBTLBq3tJkD72xQ9Gqw== +vscode-windows-ca-certs@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.2.0.tgz#086f0f4de57e2760a35ac6920831bff246237115" + integrity sha512-YBrJRT0zos+Yb1Qdn73GD8QZr7pa2IE96b5Y1hmmp6XeR8aYB7Iiq5gDAF/+/AxL+caSR9KPZQ6jiYWh5biD7w== dependencies: node-addon-api "1.6.2" @@ -418,20 +418,20 @@ vscode-windows-registry@1.0.2: resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.2.tgz#b863e704a6a69c50b3098a55fbddbe595b0c124a" integrity sha512-/CLLvuOSM2Vme2z6aNyB+4Omd7hDxpf4Thrt8ImxnXeQtxzel2bClJpFQvQqK/s4oaXlkBKS7LqVLeZM+uSVIA== -xterm-addon-search@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0.tgz#fc6843bebab1873eff0c89e31f7b74bb3c4d8947" - integrity sha512-ZvRmkNBSz2dT00w0qJ3Hd5cwYoOfkVZpHou7Xxy1kO34wQglU/8Ec4DNTvU27sS9BUzEg8kUcTTru0DxhJXrTA== +xterm-addon-search@0.4.0-beta4: + version "0.4.0-beta4" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0-beta4.tgz#7762ea342c6b4f5e824d83466bd93793c9d7d779" + integrity sha512-TIbEBVhydGIxcyu/CfKJbD+BKHisMGbkAfaWlCPaWis2Xmw8yE7CKrCPn+lhZYl1MdjDVEmb8lQI6WetbC2OZA== xterm-addon-web-links@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2" integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ== -xterm@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0.tgz#b9980b2ae18c64ed31bcc95eace3bcecffebbbd9" - integrity sha512-oNfLqt+LmghLPOt5UcskP5Km1fXpTBHsTZ99nxJKY2N0MNFXBKIVXUcNNhHCa74JGZFMGhLT58A/UN3HcPXSfg== +xterm@4.3.0-beta17: + version "4.3.0-beta17" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.3.0-beta17.tgz#c038cc00cb5be33d2a5f083255c329d9ed186565" + integrity sha512-Lgz7vL12MBKJSgK/UXJF22Yw+uEXEE7YZDWfUD+/jbHAKN4geLQJ/Y/b3gxjLL020dnYZuayfKOr2KWdhKsmCA== yauzl@^2.9.2: version "2.10.0" diff --git a/src/bootstrap.js b/src/bootstrap.js index c3815b745cc..b035adc9f41 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -263,7 +263,12 @@ exports.configurePortable = function () { } if (isTempPortable) { - process.env[process.platform === 'win32' ? 'TEMP' : 'TMPDIR'] = portableTempPath; + if (process.platform === 'win32') { + process.env['TMP'] = portableTempPath; + process.env['TEMP'] = portableTempPath; + } else { + process.env['TMPDIR'] = portableTempPath; + } } return { diff --git a/src/main.js b/src/main.js index d5f4c907fe7..7242b0cb156 100644 --- a/src/main.js +++ b/src/main.js @@ -147,13 +147,9 @@ function configureCommandlineSwitchesSync(cliArgs) { if (argvValue === true || argvValue === 'true') { if (argvKey === 'disable-hardware-acceleration') { app.disableHardwareAcceleration(); // needs to be called explicitly - } else if (argvKey === 'disable-color-correct-rendering') { - app.commandLine.appendSwitch('disable-color-correct-rendering'); // needs to be called exactly like this (https://github.com/microsoft/vscode/issues/84154) } else { - app.commandLine.appendArgument(argvKey); + app.commandLine.appendSwitch(argvKey); } - } else { - app.commandLine.appendSwitch(argvKey, argvValue); } }); diff --git a/src/tsconfig.base.json b/src/tsconfig.base.json index 907c210b530..44595cf5246 100644 --- a/src/tsconfig.base.json +++ b/src/tsconfig.base.json @@ -10,6 +10,7 @@ "alwaysStrict": true, "strictBindCallApply": true, "strictNullChecks": true, + "strictPropertyInitialization": true, "forceConsistentCasingInFileNames": true, "baseUrl": ".", "paths": { diff --git a/src/typings/jschardet.d.ts b/src/typings/jschardet.d.ts deleted file mode 100644 index f252a47fd09..00000000000 --- a/src/typings/jschardet.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -declare module 'jschardet' { - export interface IDetectedMap { - encoding: string, - confidence: number - } - export function detect(buffer: Buffer): IDetectedMap; - - export const Constants: { - MINIMUM_THRESHOLD: number, - } -} \ No newline at end of file diff --git a/src/typings/vscode-proxy-agent.d.ts b/src/typings/vscode-proxy-agent.d.ts deleted file mode 100644 index a997fa97801..00000000000 --- a/src/typings/vscode-proxy-agent.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode-proxy-agent'; diff --git a/src/typings/vscode-windows-ca-certs.d.ts b/src/typings/vscode-windows-ca-certs.d.ts deleted file mode 100644 index f923eb8a8ac..00000000000 --- a/src/typings/vscode-windows-ca-certs.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode-windows-ca-certs'; diff --git a/src/typings/windows-foreground-love.d.ts b/src/typings/windows-foreground-love.d.ts deleted file mode 100644 index f7d20f13aef..00000000000 --- a/src/typings/windows-foreground-love.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module 'windows-foreground-love' { - - export function allowSetForegroundWindow(pid?: number): boolean; - -} \ No newline at end of file diff --git a/src/vs/base/browser/canIUse.ts b/src/vs/base/browser/canIUse.ts index 157ce940da5..061d1bfc74f 100644 --- a/src/vs/base/browser/canIUse.ts +++ b/src/vs/base/browser/canIUse.ts @@ -6,6 +6,12 @@ import * as browser from 'vs/base/browser/browser'; import * as platform from 'vs/base/common/platform'; +export const enum KeyboardSupport { + Always, + FullScreen, + None +} + /** * Browser feature we can support in current platform, browser and environment. */ @@ -37,9 +43,17 @@ export const BrowserFeatures = { return true; })() }, - /* - * Full Keyboard Support in Full Screen Mode or Standablone - */ - fullKeyboard: !!(navigator).keyboard || browser.isSafari, + keyboard: (() => { + if (platform.isNative || browser.isStandalone) { + return KeyboardSupport.Always; + } + + if ((navigator).keyboard || browser.isSafari) { + return KeyboardSupport.FullScreen; + } + + return KeyboardSupport.None; + })(), + touch: 'ontouchstart' in window || navigator.maxTouchPoints > 0 || window.navigator.msMaxTouchPoints > 0 }; diff --git a/src/vs/base/browser/fastDomNode.ts b/src/vs/base/browser/fastDomNode.ts index 6dfec19f492..180eacdbd0f 100644 --- a/src/vs/base/browser/fastDomNode.ts +++ b/src/vs/base/browser/fastDomNode.ts @@ -26,6 +26,7 @@ export class FastDomNode { private _position: string; private _visibility: string; private _layerHint: boolean; + private _contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint'; constructor(domNode: T) { this.domNode = domNode; @@ -47,6 +48,7 @@ export class FastDomNode { this._position = ''; this._visibility = ''; this._layerHint = false; + this._contain = 'none'; } public setMaxWidth(maxWidth: number): void { @@ -206,6 +208,14 @@ export class FastDomNode { (this.domNode.style).willChange = this._layerHint ? 'transform' : 'auto'; } + public setContain(contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint'): void { + if (this._contain === contain) { + return; + } + this._contain = contain; + (this.domNode.style).contain = this._contain; + } + public setAttribute(name: string, value: string): void { this.domNode.setAttribute(name, value); } diff --git a/src/vs/base/browser/ui/actionbar/actionbar.css b/src/vs/base/browser/ui/actionbar/actionbar.css index 60979ab095d..623ff4d7421 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.css +++ b/src/vs/base/browser/ui/actionbar/actionbar.css @@ -90,4 +90,5 @@ display: flex; align-items: center; justify-content: center; + margin-right: 10px; } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css index b01ce8e6e12..753d7079299 100644 --- a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css +++ b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.css @@ -5,7 +5,7 @@ @font-face { font-family: "codicon"; - src: url("./codicon.ttf?7197ad7e38e9644da47ec42494d56501") format("truetype"); + src: url("./codicon.ttf?3443fb4013ab5a04c23a30f912dd6627") format("truetype"); } .codicon[class*='codicon-'] { @@ -19,11 +19,6 @@ user-select: none; -webkit-user-select: none; -ms-user-select: none; - - /* Hack to get web rendering to align to pixel grid */ - transform: rotate(0); - -webkit-transform: rotate(0.1deg); - -moz-transform: rotate(0); } diff --git a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf index a5b71658491..ba3474205da 100644 Binary files a/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf and b/src/vs/base/browser/ui/codiconLabel/codicon/codicon.ttf differ diff --git a/src/vs/base/browser/ui/dialog/dialog.css b/src/vs/base/browser/ui/dialog/dialog.css index 1ee1c9860cc..4cb5c5ce13b 100644 --- a/src/vs/base/browser/ui/dialog/dialog.css +++ b/src/vs/base/browser/ui/dialog/dialog.css @@ -27,12 +27,12 @@ min-width: 500px; max-width: 90%; min-height: 75px; - padding: 5px; + padding: 10px; } /** Dialog: Title Actions Row */ .monaco-workbench .dialog-box .dialog-toolbar-row { - padding-right: 1px; + padding-bottom: 4px; } .monaco-workbench .dialog-box .action-label { @@ -59,17 +59,17 @@ .monaco-workbench .dialog-box .dialog-message-row { display: flex; flex-grow: 1; - padding: 10px 15px 20px; align-items: center; + padding: 0 10px; } .monaco-workbench .dialog-box .dialog-message-row .dialog-icon { - flex: 0 0 40px; - height: 40px; + flex: 0 0 48px; + height: 48px; align-self: baseline; background-position: center; background-repeat: no-repeat; - background-size: 40px; + background-size: 48px; } .vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending { @@ -121,7 +121,7 @@ flex-direction: column; overflow: hidden; text-overflow: ellipsis; - padding-left: 20px; + padding-left: 24px; user-select: text; -webkit-user-select: text; -ms-user-select: text; @@ -136,7 +136,6 @@ flex: 1; /* let the message always grow */ white-space: normal; word-wrap: break-word; /* never overflow long words, but break to next line */ - padding-bottom: 10px; } /** Dialog: Details */ @@ -144,6 +143,7 @@ line-height: 22px; flex: 1; /* let the message always grow */ opacity: .9; + margin-top: 8px; } .monaco-workbench .dialog-box .dialog-message-row .dialog-message-container .dialog-message a:focus { @@ -175,6 +175,7 @@ .monaco-workbench .dialog-box > .dialog-buttons-row { display: flex; white-space: nowrap; + padding: 20px 10px 10px; } /** Dialog: Buttons */ diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 48a5214a0d2..65ff0de7f6e 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -1198,7 +1198,11 @@ export class List implements ISpliceable, IDisposable { this.view = new ListView(container, virtualDelegate, renderers, viewOptions); - this.updateAriaRole(); + if (typeof _options.ariaRole !== 'string') { + this.view.domNode.setAttribute('role', ListAriaRootRole.TREE); + } else { + this.view.domNode.setAttribute('role', _options.ariaRole); + } this.styleElement = DOM.createStyleSheet(this.view.domNode); @@ -1610,19 +1614,9 @@ export class List implements ISpliceable, IDisposable { this.view.domNode.removeAttribute('aria-activedescendant'); } - this.updateAriaRole(); - DOM.toggleClass(this.view.domNode, 'element-focused', focus.length > 0); } - private updateAriaRole(): void { - if (typeof this.options.ariaRole !== 'string') { - this.view.domNode.setAttribute('role', ListAriaRootRole.TREE); - } else { - this.view.domNode.setAttribute('role', this.options.ariaRole); - } - } - private _onSelectionChange(): void { const selection = this.selection.get(); diff --git a/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts index 4e9245ade07..b1d48bc7cf8 100644 --- a/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +++ b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts @@ -99,6 +99,7 @@ export abstract class AbstractScrollbar extends Widget { this.slider.setHeight(height); } this.slider.setLayerHinting(true); + this.slider.setContain('strict'); this.domNode.domNode.appendChild(this.slider.domNode); diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 50ab5ce9be3..9a5dd74b4f5 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -264,7 +264,7 @@ function dfs(node: IAsyncDataTreeNode, fn: (node: IAsyncDa export class AsyncDataTree implements IDisposable { protected readonly tree: ObjectTree, TFilterData>; - private readonly root: IAsyncDataTreeNode; + protected readonly root: IAsyncDataTreeNode; private readonly nodes = new Map>(); private readonly sorter?: ITreeSorter; private readonly collapseByDefault?: { (e: T): boolean; }; @@ -859,7 +859,7 @@ export class AsyncDataTree implements IDisposable return childrenToRefresh; } - private render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void { + protected render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void { const children = node.children.map(node => this.asTreeElement(node, viewStateContext)); this.tree.setChildren(node === this.root ? null : node, children); @@ -1031,7 +1031,7 @@ export interface ICompressibleAsyncDataTreeOptionsUpdate extends IAsyncDataTreeO export class CompressibleAsyncDataTree extends AsyncDataTree { - protected readonly tree: CompressibleObjectTree, TFilterData>; + protected readonly tree!: CompressibleObjectTree, TFilterData>; protected readonly compressibleNodeMapper: CompressibleAsyncDataTreeNodeMapper = new WeakMapper(node => new CompressibleAsyncDataTreeNodeWrapper(node)); constructor( @@ -1098,4 +1098,75 @@ export class CompressibleAsyncDataTree extends As return { focus, selection, expanded, scrollTop: this.scrollTop }; } + + protected render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): void { + if (!this.identityProvider) { + return super.render(node, viewStateContext); + } + + // Preserve traits across compressions. Hacky but does the trick. + // This is hard to fix properly since it requires rewriting the traits + // across trees and lists. Let's just keep it this way for now. + const getId = (element: T) => this.identityProvider!.getId(element).toString(); + const getUncompressedIds = (nodes: IAsyncDataTreeNode[]): Set => { + const result = new Set(); + + for (const node of nodes) { + const compressedNode = this.tree.getCompressedTreeNode(node === this.root ? null : node); + + if (!compressedNode.element) { + continue; + } + + for (const node of compressedNode.element.elements) { + result.add(getId(node.element as T)); + } + } + + return result; + }; + + const oldSelection = getUncompressedIds(this.tree.getSelection() as IAsyncDataTreeNode[]); + const oldFocus = getUncompressedIds(this.tree.getFocus() as IAsyncDataTreeNode[]); + + super.render(node, viewStateContext); + + const selection = this.getSelection(); + let didChangeSelection = false; + + const focus = this.getFocus(); + let didChangeFocus = false; + + const visit = (node: ITreeNode> | null, TFilterData>) => { + const compressedNode = node.element; + + if (compressedNode) { + for (let i = 0; i < compressedNode.elements.length; i++) { + const id = getId(compressedNode.elements[i].element as T); + + if (oldSelection.has(id)) { + selection.push(compressedNode.elements[compressedNode.elements.length - 1].element as T); + didChangeSelection = true; + } + + if (oldFocus.has(id)) { + focus.push(compressedNode.elements[compressedNode.elements.length - 1].element as T); + didChangeFocus = true; + } + } + } + + node.children.forEach(visit); + }; + + visit(this.tree.getCompressedTreeNode(node === this.root ? null : node)); + + if (didChangeSelection) { + this.setSelection(selection); + } + + if (didChangeFocus) { + this.setFocus(focus); + } + } } diff --git a/src/vs/base/node/encoding.ts b/src/vs/base/node/encoding.ts index 0df9dbd26c2..c4cd563ef8f 100644 --- a/src/vs/base/node/encoding.ts +++ b/src/vs/base/node/encoding.ts @@ -199,27 +199,25 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | VSBuffer | null, return null; } -const MINIMUM_THRESHOLD = 0.2; -const IGNORE_ENCODINGS = ['ascii', 'utf-8', 'utf-16', 'utf-32']; - /** * Guesses the encoding from buffer. */ async function guessEncodingByBuffer(buffer: Buffer): Promise { const jschardet = await import('jschardet'); - jschardet.Constants.MINIMUM_THRESHOLD = MINIMUM_THRESHOLD; - const guessed = jschardet.detect(buffer); if (!guessed || !guessed.encoding) { return null; } - const enc = guessed.encoding.toLowerCase(); - - // Ignore encodings that cannot guess correctly - // (http://chardet.readthedocs.io/en/latest/supported-encodings.html) - if (0 <= IGNORE_ENCODINGS.indexOf(enc)) { + // Ignore 'ascii' as guessed encoding because that + // is almost never what we want, rather fallback + // to the configured encoding then. Otherwise, + // opening a ascii-only file with auto guessing + // enabled will put the file into 'ascii' mode + // and thus typing any special characters is + // not possible anymore. + if (guessed.encoding.toLowerCase() === 'ascii') { return null; } diff --git a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts index 7a3a473d970..dc7df956ff2 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenWidget.ts @@ -134,6 +134,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { private styles: IQuickOpenStyles; // @ts-ignore (legacy widget - to be replaced with quick input) private renderer: Renderer; + private keyDownSeenSinceShown = false; constructor(container: HTMLElement, callbacks: IQuickOpenCallbacks, options: IQuickOpenOptions) { super(); @@ -170,6 +171,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { this._register(DOM.addDisposableListener(this.element, DOM.EventType.FOCUS, e => this.gainingFocus(), true)); this._register(DOM.addDisposableListener(this.element, DOM.EventType.BLUR, e => this.loosingFocus(e), true)); this._register(DOM.addDisposableListener(this.element, DOM.EventType.KEY_DOWN, e => { + this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); if (keyboardEvent.keyCode === KeyCode.Escape) { DOM.EventHelper.stop(e, true); @@ -220,6 +222,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { this._register(DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.INPUT, (e: Event) => this.onType())); this._register(DOM.addDisposableListener(this.inputBox.inputElement, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); const shouldOpenInBackground = this.shouldOpenInBackground(keyboardEvent); @@ -300,6 +303,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { })); this._register(DOM.addDisposableListener(this.treeContainer, DOM.EventType.KEY_DOWN, e => { + this.keyDownSeenSinceShown = true; const keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e); // Only handle when in quick navigation mode @@ -320,7 +324,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { const keyCode = keyboardEvent.keyCode; // Only handle when in quick navigation mode - if (!this.quickNavigateConfiguration) { + if (!this.quickNavigateConfiguration || !this.keyDownSeenSinceShown) { return; } @@ -595,6 +599,7 @@ export class QuickOpenWidget extends Disposable implements IModelProvider { this.visible = true; this.isLoosingFocus = false; this.quickNavigateConfiguration = options ? options.quickNavigateConfiguration : undefined; + this.keyDownSeenSinceShown = false; // Adjust UI for quick navigate mode if (this.quickNavigateConfiguration) { diff --git a/src/vs/base/test/node/encoding/encoding.test.ts b/src/vs/base/test/node/encoding/encoding.test.ts index 77ad22264cf..eef17fbddb6 100644 --- a/src/vs/base/test/node/encoding/encoding.test.ts +++ b/src/vs/base/test/node/encoding/encoding.test.ts @@ -189,6 +189,20 @@ suite('Encoding', () => { assert.equal(mimes.seemsBinary, false); }); + test('autoGuessEncoding (UTF8)', async function () { + const file = getPathFromAmdModule(require, './fixtures/some_file.css'); + const buffer = await readExactlyByFile(file, 512 * 8); + const mimes = await encoding.detectEncodingFromBuffer(buffer, true); + assert.equal(mimes.encoding, 'utf8'); + }); + + test('autoGuessEncoding (ASCII)', async function () { + const file = getPathFromAmdModule(require, './fixtures/some_ansi.css'); + const buffer = await readExactlyByFile(file, 512 * 8); + const mimes = await encoding.detectEncodingFromBuffer(buffer, true); + assert.equal(mimes.encoding, null); + }); + test('autoGuessEncoding (ShiftJIS)', async function () { const file = getPathFromAmdModule(require, './fixtures/some.shiftjis.txt'); const buffer = await readExactlyByFile(file, 512 * 8); diff --git a/src/vs/base/test/node/encoding/fixtures/some_file.css b/src/vs/base/test/node/encoding/fixtures/some_file.css new file mode 100644 index 00000000000..e4e1350019f --- /dev/null +++ b/src/vs/base/test/node/encoding/fixtures/some_file.css @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------- +The base color for this template is #5c87b2. If you'd like +to use a different color start by replacing all instances of +#5c87b2 with your new color. + +öäüßßß +----------------------------------------------------------*/ +body +{ + background-color: #5c87b2; + font-size: .75em; + font-family: Segoe UI, Verdana, Helvetica, Sans-Serif; + margin: 8px; + padding: 0; + color: #696969; +} + +h1, h2, h3, h4, h5, h6 +{ + color: #000; + font-size: 40px; + margin: 0px; +} + +textarea +{ + font-family: Consolas +} + +#results +{ + margin-top: 2em; + margin-left: 2em; + color: black; + font-size: medium; +} + diff --git a/src/vs/base/test/node/encoding/fixtures/some_utf16be.css b/src/vs/base/test/node/encoding/fixtures/some_utf16be.css index 30c3b9d38ba..89443814000 100644 Binary files a/src/vs/base/test/node/encoding/fixtures/some_utf16be.css and b/src/vs/base/test/node/encoding/fixtures/some_utf16be.css differ diff --git a/src/vs/base/test/node/encoding/fixtures/some_utf16le.css b/src/vs/base/test/node/encoding/fixtures/some_utf16le.css index aea04aa2cd1..243daee1f09 100644 Binary files a/src/vs/base/test/node/encoding/fixtures/some_utf16le.css and b/src/vs/base/test/node/encoding/fixtures/some_utf16le.css differ diff --git a/src/vs/base/test/node/encoding/fixtures/some_utf8.css b/src/vs/base/test/node/encoding/fixtures/some_utf8.css index f7b51e752bb..e4e1350019f 100644 --- a/src/vs/base/test/node/encoding/fixtures/some_utf8.css +++ b/src/vs/base/test/node/encoding/fixtures/some_utf8.css @@ -7,6 +7,8 @@ The base color for this template is #5c87b2. If you'd like to use a different color start by replacing all instances of #5c87b2 with your new color. + +öäüßßß ----------------------------------------------------------*/ body { @@ -25,12 +27,12 @@ h1, h2, h3, h4, h5, h6 margin: 0px; } -textarea +textarea { font-family: Consolas } -#results +#results { margin-top: 2em; margin-left: 2em; diff --git a/src/vs/base/node/test/fixtures/extract.zip b/src/vs/base/test/node/zip/fixtures/extract.zip similarity index 100% rename from src/vs/base/node/test/fixtures/extract.zip rename to src/vs/base/test/node/zip/fixtures/extract.zip diff --git a/src/vs/base/node/test/zip.test.ts b/src/vs/base/test/node/zip/zip.test.ts similarity index 100% rename from src/vs/base/node/test/zip.test.ts rename to src/vs/base/test/node/zip/zip.test.ts diff --git a/src/vs/code/browser/workbench/workbench.ts b/src/vs/code/browser/workbench/workbench.ts index a599f5a7ebf..28b0e9a3b15 100644 --- a/src/vs/code/browser/workbench/workbench.ts +++ b/src/vs/code/browser/workbench/workbench.ts @@ -11,7 +11,6 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { request } from 'vs/base/parts/request/browser/request'; import { isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows'; import { isEqual } from 'vs/base/common/resources'; -import { isStandalone } from 'vs/base/browser/browser'; interface ICredential { service: string; @@ -223,7 +222,7 @@ class WorkspaceProvider implements IWorkspaceProvider { if (options?.reuse) { window.location.href = targetHref; } else { - if (isStandalone) { + if (this.isRunningInPWA()) { // TODO@ben figure out why browser.isStandalone would not work? window.open(targetHref, '_blank', 'toolbar=no'); // ensures to open another 'standalone' window! } else { window.open(targetHref); @@ -232,6 +231,10 @@ class WorkspaceProvider implements IWorkspaceProvider { } } + private isRunningInPWA(): boolean { + return (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches); + } + private createTargetUrl(workspace: IWorkspace, options?: { reuse?: boolean, payload?: object }): string | undefined { // Empty diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 9ddf3c0eca9..1492e7710c1 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -59,7 +59,7 @@ import { IElectronService } from 'vs/platform/electron/node/electron'; import { LoggerService } from 'vs/platform/log/node/loggerService'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { IAuthTokenService } from 'vs/platform/auth/common/auth'; -import { AuthTokenService } from 'vs/platform/auth/common/authTokenService'; +import { AuthTokenService } from 'vs/platform/auth/electron-browser/authTokenService'; import { AuthTokenChannel } from 'vs/platform/auth/common/authTokenIpc'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService'; diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 2abbdf31166..b55f4095e3b 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -60,7 +60,7 @@ const enum WindowError { export class CodeWindow extends Disposable implements ICodeWindow { private static readonly MIN_WIDTH = 600; - private static readonly MIN_HEIGHT = 600; + private static readonly MIN_HEIGHT = 270; private static readonly MAX_URL_LENGTH = 2 * 1024 * 1024; // https://cs.chromium.org/chromium/src/url/url_constants.cc?l=32 diff --git a/src/vs/code/test/electron-main/nativeHelpers.test.ts b/src/vs/code/test/electron-main/nativeHelpers.test.ts index c8ffd0c8dbc..199fa7acaf7 100644 --- a/src/vs/code/test/electron-main/nativeHelpers.test.ts +++ b/src/vs/code/test/electron-main/nativeHelpers.test.ts @@ -28,7 +28,9 @@ suite('Windows Native Helpers', () => { }); test('vscode-windows-ca-certs', async () => { - const windowsCerts = await import('vscode-windows-ca-certs'); + const windowsCerts = await new Promise((resolve, reject) => { + require(['vscode-windows-ca-certs'], resolve, reject); + }); assert.ok(windowsCerts, 'Unable to load vscode-windows-ca-certs dependency.'); }); diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index ec222be4354..70cd98a030a 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -406,6 +406,10 @@ export class TextAreaHandler extends ViewPart { this._textAreaInput.focusTextArea(); } + public refreshFocusState() { + this._textAreaInput.refreshFocusState(); + } + // --- end view API private _primaryCursorVisibleRange: HorizontalPosition | null = null; diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 6e379a0400f..daecfbc4f68 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -163,7 +163,7 @@ export class TextAreaInput extends Disposable { private _isDoingComposition: boolean; private _nextCommand: ReadFromTextArea; - constructor(host: ITextAreaInputHost, textArea: FastDomNode) { + constructor(host: ITextAreaInputHost, private textArea: FastDomNode) { super(); this._host = host; this._textArea = this._register(new TextAreaWrapper(textArea)); @@ -483,6 +483,14 @@ export class TextAreaInput extends Disposable { return this._hasFocus; } + public refreshFocusState(): void { + if (document.body.contains(this.textArea.domNode) && document.activeElement === this.textArea.domNode) { + this._setHasFocus(true); + } else { + this._setHasFocus(false); + } + } + private _setHasFocus(newHasFocus: boolean): void { if (this._hasFocus === newHasFocus) { // no change diff --git a/src/vs/editor/browser/services/openerService.ts b/src/vs/editor/browser/services/openerService.ts index 9902634b3e2..48175adfb42 100644 --- a/src/vs/editor/browser/services/openerService.ts +++ b/src/vs/editor/browser/services/openerService.ts @@ -13,7 +13,7 @@ import { equalsIgnoreCase } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; -import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions } from 'vs/platform/opener/common/opener'; +import { IOpener, IOpenerService, IValidator, IExternalUriResolver, OpenOptions, ResolveExternalUriOptions, IResolvedExternalUri, IExternalOpener } from 'vs/platform/opener/common/opener'; import { EditorOpenContext } from 'vs/platform/editor/common/editor'; export class OpenerService extends Disposable implements IOpenerService { @@ -23,12 +23,22 @@ export class OpenerService extends Disposable implements IOpenerService { private readonly _openers = new LinkedList(); private readonly _validators = new LinkedList(); private readonly _resolvers = new LinkedList(); + private _externalOpener: IExternalOpener; constructor( @ICodeEditorService private readonly _editorService: ICodeEditorService, @ICommandService private readonly _commandService: ICommandService, ) { super(); + + // Default external opener is going through window.open() + this._externalOpener = { + openExternal: href => { + dom.windowOpenNoOpener(href); + + return Promise.resolve(true); + } + }; } registerOpener(opener: IOpener): IDisposable { @@ -49,6 +59,10 @@ export class OpenerService extends Disposable implements IOpenerService { return { dispose: remove }; } + setExternalOpener(externalOpener: IExternalOpener): void { + this._externalOpener = externalOpener; + } + async open(resource: URI, options?: OpenOptions): Promise { // no scheme ?!? @@ -75,7 +89,7 @@ export class OpenerService extends Disposable implements IOpenerService { return this._doOpen(resource, options); } - async resolveExternalUri(resource: URI, options?: { readonly allowTunneling?: boolean }): Promise<{ resolved: URI, dispose(): void }> { + async resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise { for (const resolver of this._resolvers.toArray()) { const result = await resolver.resolveExternalUri(resource, options); if (result) { @@ -89,13 +103,8 @@ export class OpenerService extends Disposable implements IOpenerService { private async _doOpen(resource: URI, options: OpenOptions | undefined): Promise { const { scheme, path, query, fragment } = resource; - if (equalsIgnoreCase(scheme, Schemas.mailto) || options?.openExternal) { - // open default mail application - return this._doOpenExternal(resource, options); - } - - if (equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { - // open link in default browser + if (options?.openExternal || equalsIgnoreCase(scheme, Schemas.mailto) || equalsIgnoreCase(scheme, Schemas.http) || equalsIgnoreCase(scheme, Schemas.https)) { + // open externally return this._doOpenExternal(resource, options); } @@ -149,9 +158,10 @@ export class OpenerService extends Disposable implements IOpenerService { private async _doOpenExternal(resource: URI, options: OpenOptions | undefined): Promise { const { resolved } = await this.resolveExternalUri(resource, options); - dom.windowOpenNoOpener(encodeURI(resolved.toString(true))); - return true; + // TODO@Jo neither encodeURI nor toString(true) should be needed + // once we go with URL and not URI + return this._externalOpener.openExternal(encodeURI(resolved.toString(true))); } dispose() { diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index 15f286d6abe..42ef1f6f542 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -528,6 +528,10 @@ export class View extends ViewEventHandler { return this._textAreaHandler.isFocused(); } + public refreshFocusState() { + this._textAreaHandler.refreshFocusState(); + } + public addContentWidget(widgetData: IContentWidgetData): void { this.contentWidgets.addWidget(widgetData.widget); this.layoutContentWidget(widgetData); diff --git a/src/vs/editor/browser/viewParts/lines/viewLines.ts b/src/vs/editor/browser/viewParts/lines/viewLines.ts index 852d6125985..00b20578698 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLines.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLines.ts @@ -544,6 +544,7 @@ export class ViewLines extends ViewPart implements IVisibleLinesHost, // (3) handle scrolling this._linesContent.setLayerHinting(this._canUseLayerHinting); + this._linesContent.setContain('strict'); const adjustedScrollTop = this._context.viewLayout.getCurrentScrollTop() - viewportData.bigNumbersDelta; this._linesContent.setTop(-adjustedScrollTop); this._linesContent.setLeft(-this._context.viewLayout.getCurrentScrollLeft()); diff --git a/src/vs/editor/browser/viewParts/margin/margin.ts b/src/vs/editor/browser/viewParts/margin/margin.ts index 1208e3c56c9..8181e2f8aa8 100644 --- a/src/vs/editor/browser/viewParts/margin/margin.ts +++ b/src/vs/editor/browser/viewParts/margin/margin.ts @@ -78,6 +78,7 @@ export class Margin extends ViewPart { public render(ctx: RestrictedRenderingContext): void { this._domNode.setLayerHinting(this._canUseLayerHinting); + this._domNode.setContain('strict'); const adjustedScrollTop = ctx.scrollTop - ctx.bigNumbersDelta; this._domNode.setTop(-adjustedScrollTop); diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 5ff05c88358..8e50b1e0e2d 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -503,6 +503,7 @@ export class Minimap extends ViewPart { this._slider.setPosition('absolute'); this._slider.setClassName('minimap-slider'); this._slider.setLayerHinting(true); + this._slider.setContain('strict'); this._domNode.appendChild(this._slider); this._sliderHorizontal = createFastDomNode(document.createElement('div')); diff --git a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts index a4e988745cb..687b9985268 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts @@ -215,6 +215,7 @@ export class DecorationsOverviewRuler extends ViewPart { this._domNode.setClassName('decorationsOverviewRuler'); this._domNode.setPosition('absolute'); this._domNode.setLayerHinting(true); + this._domNode.setContain('strict'); this._domNode.setAttribute('aria-hidden', 'true'); this._updateSettings(false); diff --git a/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts index 7b9ef090d2a..b75ba0ae422 100644 --- a/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts +++ b/src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts @@ -26,6 +26,7 @@ export class OverviewRuler extends ViewEventHandler implements IOverviewRuler { this._domNode.setClassName(cssClassName); this._domNode.setPosition('absolute'); this._domNode.setLayerHinting(true); + this._domNode.setContain('strict'); this._zoneManager = new OverviewZoneManager((lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber)); this._zoneManager.setDOMWidth(0); diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index f387c1308e8..83e47a48f1d 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -869,9 +869,11 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE } public onVisible(): void { + this._modelData?.view.refreshFocusState(); } public onHide(): void { + this._modelData?.view.refreshFocusState(); } public getContribution(id: string): T { diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index c7f50efd2d9..5ef39172f5e 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -413,14 +413,18 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed } -const configurationRegistry = Registry.as(Extensions.Configuration); -const editorConfiguration: IConfigurationNode = { +export const editorConfigurationBaseNode = Object.freeze({ id: 'editor', order: 5, type: 'object', title: nls.localize('editorConfigurationTitle', "Editor"), overridable: true, scope: ConfigurationScope.RESOURCE, +}); + +const configurationRegistry = Registry.as(Extensions.Configuration); +const editorConfiguration: IConfigurationNode = { + ...editorConfigurationBaseNode, properties: { 'editor.tabSize': { type: 'number', diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index b20246a3734..de2c41dddd3 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -3155,10 +3155,10 @@ export const EditorOptions = { ['default', 'all'] as const, { enumDescriptions: [ - nls.localize('cursorSurroundingLinesStyle.default', "`cursorSurroundingLines` is enforced only when triggered from keyboard and api"), + nls.localize('cursorSurroundingLinesStyle.default', "`cursorSurroundingLines` is enforced only when triggered via the keyboard or API."), nls.localize('cursorSurroundingLinesStyle.all', "`cursorSurroundingLines` is enforced always.") ], - description: nls.localize('cursorSurroundingLinesStyle', "Controls when `cursorSurroundingLines` should be enforced") + description: nls.localize('cursorSurroundingLinesStyle', "Controls when `cursorSurroundingLines` should be enforced.") } )), cursorWidth: register(new EditorIntOption( diff --git a/src/vs/editor/contrib/codeAction/codeActionUi.ts b/src/vs/editor/contrib/codeAction/codeActionUi.ts index 7e80fdaff8c..8db5d28fa24 100644 --- a/src/vs/editor/contrib/codeAction/codeActionUi.ts +++ b/src/vs/editor/contrib/codeAction/codeActionUi.ts @@ -30,7 +30,7 @@ export class CodeActionUi extends Disposable { quickFixActionId: string, preferredFixActionId: string, private readonly delegate: { - applyCodeAction: (action: CodeAction, regtriggerAfterApply: boolean) => void + applyCodeAction: (action: CodeAction, regtriggerAfterApply: boolean) => Promise }, @IContextMenuService contextMenuService: IContextMenuService, @IKeybindingService keybindingService: IKeybindingService, @@ -81,7 +81,7 @@ export class CodeActionUi extends Disposable { // Apply if we only have one action or requested autoApply if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && actions.actions.length === 1)) { try { - this.delegate.applyCodeAction(actions.actions[0], false); + await this.delegate.applyCodeAction(actions.actions[0], false); } finally { actions.dispose(); } diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index a9eb3766de9..e61b9acafb1 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -326,7 +326,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { return; } - this._currentResolveCodeLensSymbolsPromise = createCancelablePromise(token => { + const resolvePromise = createCancelablePromise(token => { const promises = toResolve.map((request, i) => { @@ -351,16 +351,21 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { return Promise.all(promises); }); + this._currentResolveCodeLensSymbolsPromise = resolvePromise; this._currentResolveCodeLensSymbolsPromise.then(() => { if (this._currentCodeLensModel) { // update the cached state with new resolved items this._codeLensCache.put(model, this._currentCodeLensModel); } this._oldCodeLensModels.clear(); // dispose old models once we have updated the UI with the current model - this._currentResolveCodeLensSymbolsPromise = undefined; + if (resolvePromise === this._currentResolveCodeLensSymbolsPromise) { + this._currentResolveCodeLensSymbolsPromise = undefined; + } }, err => { onUnexpectedError(err); // can also be cancellation! - this._currentResolveCodeLensSymbolsPromise = undefined; + if (resolvePromise === this._currentResolveCodeLensSymbolsPromise) { + this._currentResolveCodeLensSymbolsPromise = undefined; + } }); } } diff --git a/src/vs/editor/contrib/gotoSymbol/goToCommands.ts b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts index 8fab75a9709..5ec0555a5ef 100644 --- a/src/vs/editor/contrib/gotoSymbol/goToCommands.ts +++ b/src/vs/editor/contrib/gotoSymbol/goToCommands.ts @@ -107,8 +107,6 @@ abstract class SymbolNavigationAction extends EditorAction { protected abstract _getNoResultFoundMessage(info: IWordAtPosition | null): string; - protected abstract _getMetaTitle(model: ReferencesModel): string; - protected abstract _getAlternativeCommand(): string; protected abstract _getGoToPreference(editor: IActiveCodeEditor): GoToLocationValues; @@ -171,7 +169,7 @@ abstract class SymbolNavigationAction extends EditorAction { export class DefinitionAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getDefinitionsAtPosition(model, position, token)); + return new ReferencesModel(await getDefinitionsAtPosition(model, position, token), nls.localize('def.title', 'Definitions')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -180,10 +178,6 @@ export class DefinitionAction extends SymbolNavigationAction { : nls.localize('generic.noResults', "No definition found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('meta.title', " – {0} definitions", model.references.length) : ''; - } - protected _getAlternativeCommand(): string { return 'editor.action.goToReferences'; } @@ -295,7 +289,7 @@ registerEditorAction(class PeekDefinitionAction extends DefinitionAction { class DeclarationAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getDeclarationsAtPosition(model, position, token)); + return new ReferencesModel(await getDeclarationsAtPosition(model, position, token), nls.localize('decl.title', 'Declarations')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -304,10 +298,6 @@ class DeclarationAction extends SymbolNavigationAction { : nls.localize('decl.generic.noResults', "No declaration found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('decl.meta.title', " – {0} declarations", model.references.length) : ''; - } - protected _getAlternativeCommand(): string { return 'editor.action.goToReferences'; } @@ -352,10 +342,6 @@ registerEditorAction(class GoToDeclarationAction extends DeclarationAction { ? nls.localize('decl.noResultWord', "No declaration found for '{0}'", info.word) : nls.localize('decl.generic.noResults', "No declaration found"); } - - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('decl.meta.title', " – {0} declarations", model.references.length) : ''; - } }); registerEditorAction(class PeekDeclarationAction extends DeclarationAction { @@ -384,7 +370,7 @@ registerEditorAction(class PeekDeclarationAction extends DeclarationAction { class TypeDefinitionAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getTypeDefinitionsAtPosition(model, position, token)); + return new ReferencesModel(await getTypeDefinitionsAtPosition(model, position, token), nls.localize('typedef.title', 'Type Definitions')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -393,10 +379,6 @@ class TypeDefinitionAction extends SymbolNavigationAction { : nls.localize('goToTypeDefinition.generic.noResults', "No type definition found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('meta.typeDefinitions.title', " – {0} type definitions", model.references.length) : ''; - } - protected _getAlternativeCommand(): string { return 'editor.action.goToReferences'; } @@ -470,7 +452,7 @@ registerEditorAction(class PeekTypeDefinitionAction extends TypeDefinitionAction class ImplementationAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getImplementationsAtPosition(model, position, token)); + return new ReferencesModel(await getImplementationsAtPosition(model, position, token), nls.localize('impl.title', 'Implementations')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -479,10 +461,6 @@ class ImplementationAction extends SymbolNavigationAction { : nls.localize('goToImplementation.generic.noResults', "No implementation found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 ? nls.localize('meta.implementations.title', " – {0} implementations", model.references.length) : ''; - } - protected _getAlternativeCommand(): string { return ''; } @@ -561,7 +539,7 @@ registerEditorAction(class PeekImplementationAction extends ImplementationAction class ReferencesAction extends SymbolNavigationAction { protected async _getLocationModel(model: ITextModel, position: corePosition.Position, token: CancellationToken): Promise { - return new ReferencesModel(await getReferencesAtPosition(model, position, token)); + return new ReferencesModel(await getReferencesAtPosition(model, position, token), nls.localize('ref.title', 'References')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -570,12 +548,6 @@ class ReferencesAction extends SymbolNavigationAction { : nls.localize('references.noGeneric', "No references found"); } - protected _getMetaTitle(model: ReferencesModel): string { - return model.references.length > 1 - ? nls.localize('meta.titleReference', " – {0} references", model.references.length) - : ''; - } - protected _getAlternativeCommand(): string { return ''; } @@ -667,7 +639,7 @@ class GenericGoToLocationAction extends SymbolNavigationAction { } protected async _getLocationModel(_model: ITextModel, _position: corePosition.Position, _token: CancellationToken): Promise { - return new ReferencesModel(this._references); + return new ReferencesModel(this._references, nls.localize('generic.title', 'Locations')); } protected _getNoResultFoundMessage(info: IWordAtPosition | null): string { @@ -678,7 +650,6 @@ class GenericGoToLocationAction extends SymbolNavigationAction { return this._gotoMultipleBehaviour ?? editor.getOption(EditorOption.gotoLocation).multipleReferences; } - protected _getMetaTitle() { return ''; } protected _getAlternativeCommand() { return ''; } } @@ -736,7 +707,7 @@ CommandsRegistry.registerCommand({ return undefined; } - const references = createCancelablePromise(token => getReferencesAtPosition(control.getModel(), corePosition.Position.lift(position), token).then(references => new ReferencesModel(references))); + const references = createCancelablePromise(token => getReferencesAtPosition(control.getModel(), corePosition.Position.lift(position), token).then(references => new ReferencesModel(references, nls.localize('ref.title', 'References')))); const range = new Range(position.lineNumber, position.column, position.lineNumber, position.column); return Promise.resolve(controller.toggleWidget(range, references, false)); }); diff --git a/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts index 1b5389383e4..4d22101b994 100644 --- a/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesController.ts @@ -14,14 +14,14 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import * as editorCommon from 'vs/editor/common/editorCommon'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ReferencesModel, OneReference } from '../referencesModel'; -import { ReferenceWidget, LayoutData, ctxReferenceWidgetSearchTreeFocused } from './referencesWidget'; +import { ReferenceWidget, LayoutData } from './referencesWidget'; import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; import { Location } from 'vs/editor/common/modes'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { getOuterEditor, PeekContext } from 'vs/editor/contrib/peekView/peekView'; -import { IListService } from 'vs/platform/list/browser/listService'; +import { IListService, WorkbenchListFocusContextKey } from 'vs/platform/list/browser/listService'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; @@ -151,10 +151,8 @@ export abstract class ReferencesController implements editorCommon.IEditorContri if (this._widget && this._model && this._editor.hasModel()) { // might have been closed // set title - if (this._model.references.length === 1) { - this._widget.setMetaTitle(nls.localize('metaTitle.1', "1 result")); - } else if (!this._model.isEmpty) { - this._widget.setMetaTitle(nls.localize('metaTitle.N', "{0} results", this._model.references.length)); + if (!this._model.isEmpty) { + this._widget.setMetaTitle(nls.localize('metaTitle.N', "{0} ({1})", this._model.title, this._model.references.length)); } else { this._widget.setMetaTitle(''); } @@ -361,12 +359,12 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ mac: { primary: KeyMod.WinCtrl | KeyCode.Enter }, - when: ContextKeyExpr.and(ctxReferenceSearchVisible, ctxReferenceWidgetSearchTreeFocused), + when: ContextKeyExpr.and(ctxReferenceSearchVisible, WorkbenchListFocusContextKey), handler(accessor: ServicesAccessor) { const listService = accessor.get(IListService); - const focus = listService.lastFocusedList && listService.lastFocusedList.getFocus(); - if (focus instanceof OneReference) { - withController(accessor, controller => controller.openReference(focus, true)); + const focus = listService.lastFocusedList?.getFocus(); + if (Array.isArray(focus) && focus[0] instanceof OneReference) { + withController(accessor, controller => controller.openReference(focus[0], true)); } } }); diff --git a/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts index 0db277b7cf1..1b93c77febb 100644 --- a/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesTree.ts @@ -101,7 +101,7 @@ export class StringRepresentationProvider implements IKeyboardNavigationLabelPro export class IdentityProvider implements IIdentityProvider { getId(element: TreeElement): { toString(): string; } { - return element.uri; + return element instanceof OneReference ? element.id : element.uri; } } diff --git a/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts index 00130718f26..82f86384de4 100644 --- a/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts +++ b/src/vs/editor/contrib/gotoSymbol/peek/referencesWidget.ts @@ -23,7 +23,6 @@ import { Location } from 'vs/editor/common/modes'; import { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService'; import { AriaProvider, DataSource, Delegate, FileReferencesRenderer, OneReferenceRenderer, TreeElement, StringRepresentationProvider, IdentityProvider } from 'vs/editor/contrib/gotoSymbol/peek/referencesTree'; import * as nls from 'vs/nls'; -import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; import { WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService'; @@ -182,8 +181,6 @@ export interface SelectionEvent { readonly element?: Location; } -export const ctxReferenceWidgetSearchTreeFocused = new RawContextKey('referenceSearchTreeFocused', true); - /** * ZoneWidget that is shown inside the editor */ @@ -319,7 +316,6 @@ export class ReferenceWidget extends peekView.PeekViewWidget { this._instantiationService.createInstance(DataSource), treeOptions ); - ctxReferenceWidgetSearchTreeFocused.bindTo(this._tree.contextKeyService); // split stuff this._splitView.addView({ diff --git a/src/vs/editor/contrib/gotoSymbol/referencesModel.ts b/src/vs/editor/contrib/gotoSymbol/referencesModel.ts index 77b09ed7b0f..fa0f2c14db2 100644 --- a/src/vs/editor/contrib/gotoSymbol/referencesModel.ts +++ b/src/vs/editor/contrib/gotoSymbol/referencesModel.ts @@ -149,6 +149,7 @@ export class ReferencesModel implements IDisposable { private readonly _disposables = new DisposableStore(); private readonly _links: LocationLink[]; + private readonly _title: string; readonly groups: FileReferences[] = []; readonly references: OneReference[] = []; @@ -156,8 +157,9 @@ export class ReferencesModel implements IDisposable { readonly _onDidChangeReferenceRange = new Emitter(); readonly onDidChangeReferenceRange: Event = this._onDidChangeReferenceRange.event; - constructor(links: LocationLink[]) { + constructor(links: LocationLink[], title: string) { this._links = links; + this._title = title; // grouping and sorting const [providersFirst] = links; @@ -192,7 +194,11 @@ export class ReferencesModel implements IDisposable { } clone(): ReferencesModel { - return new ReferencesModel(this._links); + return new ReferencesModel(this._links, this._title); + } + + get title(): string { + return this._title; } get isEmpty(): boolean { diff --git a/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts b/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts index f3a0d011914..c2a1b95246a 100644 --- a/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts +++ b/src/vs/editor/contrib/gotoSymbol/test/referencesModel.test.ts @@ -21,7 +21,7 @@ suite('references', function () { }, { uri: URI.file('/src/can'), range: new Range(1, 1, 1, 1) - }]); + }], 'FOO'); let ref = model.nearestReference(URI.file('/src/can'), new Position(1, 1)); assert.equal(ref!.uri.path, '/src/can'); diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 613ec87b2de..61cf4274a0d 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -14,6 +14,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { Registry } from 'vs/platform/registry/common/platform'; import { ColorIdentifier, Extensions, IColorRegistry } from 'vs/platform/theme/common/colorRegistry'; import { Extensions as ThemingExtensions, ICssStyleCollector, IIconTheme, IThemingRegistry } from 'vs/platform/theme/common/themeService'; +import { TokenStyle, TokenClassification, ProbeScope } from 'vs/platform/theme/common/tokenClassificationRegistry'; const VS_THEME_NAME = 'vs'; const VS_DARK_THEME_NAME = 'vs-dark'; @@ -23,6 +24,7 @@ const colorRegistry = Registry.as(Extensions.ColorContribution); const themingRegistry = Registry.as(ThemingExtensions.ThemingContribution); class StandaloneTheme implements IStandaloneTheme { + public readonly id: string; public readonly themeName: string; @@ -128,6 +130,14 @@ class StandaloneTheme implements IStandaloneTheme { } return this._tokenTheme; } + + getTokenStyle(classification: TokenClassification, useDefault?: boolean | undefined): TokenStyle | undefined { + return undefined; + } + + resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined { + return undefined; + } } function isBuiltinTheme(themeName: string): themeName is BuiltinTheme { diff --git a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts index b35c23cc03a..3cb4e474b1d 100644 --- a/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts +++ b/src/vs/editor/standalone/test/browser/standaloneLanguages.test.ts @@ -54,7 +54,11 @@ suite('TokenizationSupport2Adapter', () => { defines: (color: ColorIdentifier): boolean => { throw new Error('Not implemented'); - } + }, + + getTokenStyle: () => undefined, + resolveScopes: () => undefined + }; } public getIconTheme(): IIconTheme { diff --git a/src/vs/platform/auth/common/auth.ts b/src/vs/platform/auth/common/auth.ts index 7b2961d30b0..99102a0fe93 100644 --- a/src/vs/platform/auth/common/auth.ts +++ b/src/vs/platform/auth/common/auth.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { Event } from 'vs/base/common/event'; +import { Event, Emitter } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; export const enum AuthTokenStatus { Disabled = 'Disabled', @@ -19,11 +20,10 @@ export interface IAuthTokenService { readonly status: AuthTokenStatus; readonly onDidChangeStatus: Event; + readonly _onDidGetCallback: Emitter; - getToken(): Promise; - updateToken(token: string): Promise; + getToken(): Promise; refreshToken(): Promise; - deleteToken(): Promise; - + login(callbackUri?: URI): Promise; + logout(): Promise; } - diff --git a/src/vs/platform/auth/common/authTokenIpc.ts b/src/vs/platform/auth/common/authTokenIpc.ts index a5c78c4a8dd..99a2111750c 100644 --- a/src/vs/platform/auth/common/authTokenIpc.ts +++ b/src/vs/platform/auth/common/authTokenIpc.ts @@ -22,9 +22,12 @@ export class AuthTokenChannel implements IServerChannel { switch (command) { case '_getInitialStatus': return Promise.resolve(this.service.status); case 'getToken': return this.service.getToken(); - case 'updateToken': return this.service.updateToken(args[0]); + case 'exchangeCodeForToken': + this.service._onDidGetCallback.fire(args); + return Promise.resolve(); case 'refreshToken': return this.service.refreshToken(); - case 'deleteToken': return this.service.deleteToken(); + case 'login': return this.service.login(args); + case 'logout': return this.service.logout(); } throw new Error('Invalid call'); } diff --git a/src/vs/platform/auth/electron-browser/authTokenService.ts b/src/vs/platform/auth/electron-browser/authTokenService.ts new file mode 100644 index 00000000000..9b70de53d72 --- /dev/null +++ b/src/vs/platform/auth/electron-browser/authTokenService.ts @@ -0,0 +1,266 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as crypto from 'crypto'; +import * as https from 'https'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { IProductService } from 'vs/platform/product/common/productService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { URI } from 'vs/base/common/uri'; +import { generateUuid } from 'vs/base/common/uuid'; +import { shell } from 'electron'; + +const SERVICE_NAME = 'VS Code'; +const ACCOUNT = 'MyAccount'; + +const redirectUrlAAD = 'https://vscode-redirect.azurewebsites.net/'; +const activeDirectoryEndpointUrl = 'https://login.microsoftonline.com/'; +const activeDirectoryResourceId = 'https://management.core.windows.net/'; + +const clientId = 'aebc6443-996d-45c2-90f0-388ff96faa56'; +const tenantId = 'common'; + +function parseQuery(uri: URI) { + return uri.query.split('&').reduce((prev: any, current) => { + const queryString = current.split('='); + prev[queryString[0]] = queryString[1]; + return prev; + }, {}); +} + +function toQuery(obj: any): string { + return Object.keys(obj).map(key => `${key}=${obj[key]}`).join('&'); +} + +function toBase64UrlEncoding(base64string: string) { + return base64string.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_'); // Need to use base64url encoding +} + +export interface IToken { + expiresIn: string; // How long access token is valid, in seconds + expiresOn: string; // When the access token expires in epoch time + accessToken: string; + refreshToken: string; +} + +export class AuthTokenService extends Disposable implements IAuthTokenService { + _serviceBrand: undefined; + + private _status: AuthTokenStatus = AuthTokenStatus.Disabled; + get status(): AuthTokenStatus { return this._status; } + private _onDidChangeStatus: Emitter = this._register(new Emitter()); + readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + + public readonly _onDidGetCallback: Emitter = this._register(new Emitter()); + readonly onDidGetCallback: Event = this._onDidGetCallback.event; + + private _activeToken: IToken | undefined; + + constructor( + @ICredentialsService private readonly credentialsService: ICredentialsService, + @IProductService productService: IProductService, + @IConfigurationService configurationService: IConfigurationService, + ) { + super(); + if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) { + this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT).then(storedRefreshToken => { + if (storedRefreshToken) { + this.refresh(storedRefreshToken); + } else { + this._status = AuthTokenStatus.Inactive; + } + }); + } + } + + public async login(callbackUri: URI): Promise { + const nonce = generateUuid(); + const port = (callbackUri.authority.match(/:([0-9]*)$/) || [])[1] || (callbackUri.scheme === 'https' || callbackUri.scheme === 'http' ? 443 : 80); + const state = `${callbackUri.scheme},${port},${encodeURIComponent(nonce)},${encodeURIComponent(callbackUri.query)}`; + const signInUrl = `${activeDirectoryEndpointUrl}${tenantId}/oauth2/authorize`; + + const codeVerifier = toBase64UrlEncoding(crypto.randomBytes(32).toString('base64')); + const codeChallenge = toBase64UrlEncoding(crypto.createHash('sha256').update(codeVerifier).digest('base64')); + + let uri = URI.parse(signInUrl); + uri = uri.with({ + query: `response_type=code&client_id=${encodeURIComponent(clientId)}&redirect_uri=${redirectUrlAAD}&state=${encodeURIComponent(state)}&resource=${activeDirectoryResourceId}&prompt=select_account&code_challenge_method=S256&code_challenge=${codeChallenge}` + }); + + await shell.openExternal(uri.toString(true)); + + const timeoutPromise = new Promise((resolve: (value: IToken) => void, reject) => { + const wait = setTimeout(() => { + clearTimeout(wait); + reject('Login timed out.'); + }, 1000 * 60 * 5); + }); + + return Promise.race([this.exchangeCodeForToken(clientId, tenantId, codeVerifier, state), timeoutPromise]).then(token => { + this.setToken(token); + }); + } + + public getToken(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + return Promise.resolve(this._activeToken?.accessToken); + } + + public async refreshToken(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + + if (!this._activeToken) { + throw new Error('No token to refresh'); + } + + this.refresh(this._activeToken.refreshToken); + } + + private setToken(token: IToken) { + this._activeToken = token; + this.credentialsService.setPassword(SERVICE_NAME, ACCOUNT, token.refreshToken); + this.setStatus(AuthTokenStatus.Active); + } + + private async exchangeCodeForToken(clientId: string, tenantId: string, codeVerifier: string, state: string): Promise { + let uriEventListener: IDisposable; + return new Promise((resolve: (value: IToken) => void, reject) => { + uriEventListener = this.onDidGetCallback(async (uri: URI) => { + try { + const query = parseQuery(uri); + const code = query.code; + + if (query.state !== state) { + return; + } + + const postData = toQuery({ + grant_type: 'authorization_code', + code: code, + client_id: clientId, + code_verifier: codeVerifier, + redirect_uri: redirectUrlAAD + }); + + const post = https.request({ + host: 'login.microsoftonline.com', + path: `/${tenantId}/oauth2/token`, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': postData.length + } + }, result => { + const buffer: Buffer[] = []; + result.on('data', (chunk: Buffer) => { + buffer.push(chunk); + }); + result.on('end', () => { + if (result.statusCode === 200) { + const json = JSON.parse(Buffer.concat(buffer).toString()); + resolve({ + expiresIn: json.access_token, + expiresOn: json.expires_on, + accessToken: json.access_token, + refreshToken: json.refresh_token + }); + } else { + reject(new Error('Bad!')); + } + }); + }); + + post.write(postData); + + post.end(); + post.on('error', err => { + reject(err); + }); + + } catch (e) { + reject(e); + } + }); + }).then(result => { + uriEventListener.dispose(); + return result; + }).catch(err => { + uriEventListener.dispose(); + throw err; + }); + } + + private async refresh(refreshToken: string): Promise { + return new Promise((resolve, reject) => { + const postData = toQuery({ + refresh_token: refreshToken, + client_id: clientId, + grant_type: 'refresh_token', + resource: activeDirectoryResourceId + }); + + const post = https.request({ + host: 'login.microsoftonline.com', + path: `/${tenantId}/oauth2/token`, + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Length': postData.length + } + }, result => { + const buffer: Buffer[] = []; + result.on('data', (chunk: Buffer) => { + buffer.push(chunk); + }); + result.on('end', () => { + if (result.statusCode === 200) { + const json = JSON.parse(Buffer.concat(buffer).toString()); + this.setToken({ + expiresIn: json.access_token, + expiresOn: json.expires_on, + accessToken: json.access_token, + refreshToken: json.refresh_token + }); + resolve(); + } else { + reject(new Error('Bad!')); + } + }); + }); + + post.write(postData); + + post.end(); + post.on('error', err => { + reject(err); + }); + }); + } + + async logout(): Promise { + if (this.status === AuthTokenStatus.Disabled) { + throw new Error('Not enabled'); + } + await this.credentialsService.deletePassword(SERVICE_NAME, ACCOUNT); + this._activeToken = undefined; + this.setStatus(AuthTokenStatus.Inactive); + } + + private setStatus(status: AuthTokenStatus): void { + if (this._status !== status) { + this._status = status; + this._onDidChangeStatus.fire(status); + } + } + +} + diff --git a/src/vs/platform/files/common/fileService.ts b/src/vs/platform/files/common/fileService.ts index b789748febe..d3a70db859d 100644 --- a/src/vs/platform/files/common/fileService.ts +++ b/src/vs/platform/files/common/fileService.ts @@ -209,16 +209,20 @@ export class FileService extends Disposable implements IFileService { }); } + private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise; + private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat, siblings: number | undefined, resolveMetadata: true, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise; private async toFileStat(provider: IFileSystemProvider, resource: URI, stat: IStat | { type: FileType } & Partial, siblings: number | undefined, resolveMetadata: boolean, recurse: (stat: IFileStat, siblings?: number) => boolean): Promise { // convert to file stat const fileStat: IFileStat = { resource, name: getBaseLabel(resource), + isFile: (stat.type & FileType.File) !== 0, isDirectory: (stat.type & FileType.Directory) !== 0, isSymbolicLink: (stat.type & FileType.SymbolicLink) !== 0, isReadonly: !!(provider.capabilities & FileSystemProviderCapabilities.Readonly), mtime: stat.mtime, + ctime: stat.ctime, size: stat.size, etag: etag({ mtime: stat.mtime, size: stat.size }) }; diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 0356e8dfdd3..15f2e20910b 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -207,8 +207,17 @@ export enum FileType { export interface IStat { type: FileType; + + /** + * The last modification date represented as millis from unix epoch. + */ mtime: number; + + /** + * The creation date represented as millis from unix epoch. + */ ctime: number; + size: number; } @@ -583,14 +592,21 @@ interface IBaseStat { size?: number; /** - * The last modification date represented - * as millis from unix epoch. + * The last modification date represented as millis from unix epoch. * * The value may or may not be resolved as * it is optional. */ mtime?: number; + /** + * The creation date represented as millis from unix epoch. + * + * The value may or may not be resolved as + * it is optional. + */ + ctime?: number; + /** * A unique identifier thet represents the * current state of the file or directory. @@ -608,6 +624,7 @@ interface IBaseStat { export interface IBaseStatWithMetadata extends IBaseStat { mtime: number; + ctime: number; etag: string; size: number; } @@ -618,14 +635,19 @@ export interface IBaseStatWithMetadata extends IBaseStat { export interface IFileStat extends IBaseStat { /** - * The resource is a directory + * The resource is a file. + */ + isFile: boolean; + + /** + * The resource is a directory. */ isDirectory: boolean; /** * The resource is a symbolic link. */ - isSymbolicLink?: boolean; + isSymbolicLink: boolean; /** * The children of the file stat or undefined if none. @@ -635,6 +657,7 @@ export interface IFileStat extends IBaseStat { export interface IFileStatWithMetadata extends IFileStat, IBaseStatWithMetadata { mtime: number; + ctime: number; etag: string; size: number; children?: IFileStatWithMetadata[]; @@ -703,7 +726,7 @@ export interface IResolveFileOptions { readonly resolveSingleChildDescendants?: boolean; /** - * Will resolve mtime, size and etag of files if enabled. This can have a negative impact + * Will resolve mtime, ctime, size and etag of files if enabled. This can have a negative impact * on performance and thus should only be used when these values are required. */ readonly resolveMetadata?: boolean; diff --git a/src/vs/platform/files/node/diskFileSystemProvider.ts b/src/vs/platform/files/node/diskFileSystemProvider.ts index 7c7e255d80e..0187b5d9bcc 100644 --- a/src/vs/platform/files/node/diskFileSystemProvider.ts +++ b/src/vs/platform/files/node/diskFileSystemProvider.ts @@ -80,7 +80,7 @@ export class DiskFileSystemProvider extends Disposable implements return { type: this.toType(stat, isSymbolicLink), - ctime: stat.ctime.getTime(), + ctime: stat.birthtime.getTime(), // intentionally not using ctime here, we want the creation time mtime: stat.mtime.getTime(), size: stat.size }; diff --git a/src/vs/platform/files/test/node/diskFileService.test.ts b/src/vs/platform/files/test/node/diskFileService.test.ts index 32cbb18e545..0b5b1ecf8bc 100644 --- a/src/vs/platform/files/test/node/diskFileService.test.ts +++ b/src/vs/platform/files/test/node/diskFileService.test.ts @@ -134,7 +134,7 @@ suite('Disk File Service', function () { // we see random test failures when accessing the native file system. To // diagnose further, we retry node.js file access tests up to 3 times to // rule out any random disk issue. - this.retries(3); + // this.retries(3); setup(async () => { const logService = new NullLogService(); @@ -213,23 +213,35 @@ suite('Disk File Service', function () { assert.equal(exists, false); }); - test('resolve', async () => { - const resolved = await service.resolve(URI.file(testDir), { resolveTo: [URI.file(join(testDir, 'deep'))] }); - assert.equal(resolved.children!.length, 8); + test('resolve - file', async () => { + const resource = URI.file(getPathFromAmdModule(require, './fixtures/resolver/index.html')); + const resolved = await service.resolve(resource); - const deep = (getByName(resolved, 'deep')!); - assert.equal(deep.children!.length, 4); + assert.equal(resolved.name, 'index.html'); + assert.equal(resolved.isFile, true); + assert.equal(resolved.isDirectory, false); + assert.equal(resolved.isSymbolicLink, false); + assert.equal(resolved.resource.toString(), resource.toString()); + assert.equal(resolved.children, undefined); + assert.ok(resolved.mtime! > 0); + assert.ok(resolved.ctime! > 0); + assert.ok(resolved.size! > 0); }); test('resolve - directory', async () => { const testsElements = ['examples', 'other', 'index.html', 'site.css']; - const result = await service.resolve(URI.file(getPathFromAmdModule(require, './fixtures/resolver'))); + const resource = URI.file(getPathFromAmdModule(require, './fixtures/resolver')); + const result = await service.resolve(resource); assert.ok(result); + assert.equal(result.resource.toString(), resource.toString()); + assert.equal(result.name, 'resolver'); assert.ok(result.children); assert.ok(result.children!.length > 0); assert.ok(result!.isDirectory); + assert.ok(result.mtime! > 0); + assert.ok(result.ctime! > 0); assert.equal(result.children!.length, testsElements.length); assert.ok(result.children!.every(entry => { @@ -242,12 +254,18 @@ suite('Disk File Service', function () { assert.ok(basename(value.resource.fsPath)); if (['examples', 'other'].indexOf(basename(value.resource.fsPath)) >= 0) { assert.ok(value.isDirectory); + assert.equal(value.mtime, undefined); + assert.equal(value.ctime, undefined); } else if (basename(value.resource.fsPath) === 'index.html') { assert.ok(!value.isDirectory); assert.ok(!value.children); + assert.equal(value.mtime, undefined); + assert.equal(value.ctime, undefined); } else if (basename(value.resource.fsPath) === 'site.css') { assert.ok(!value.isDirectory); assert.ok(!value.children); + assert.equal(value.mtime, undefined); + assert.equal(value.ctime, undefined); } else { assert.ok(!'Unexpected value ' + basename(value.resource.fsPath)); } @@ -260,9 +278,12 @@ suite('Disk File Service', function () { const result = await service.resolve(URI.file(getPathFromAmdModule(require, './fixtures/resolver')), { resolveMetadata: true }); assert.ok(result); + assert.equal(result.name, 'resolver'); assert.ok(result.children); assert.ok(result.children!.length > 0); assert.ok(result!.isDirectory); + assert.ok(result.mtime! > 0); + assert.ok(result.ctime! > 0); assert.equal(result.children!.length, testsElements.length); assert.ok(result.children!.every(entry => { @@ -277,18 +298,32 @@ suite('Disk File Service', function () { assert.ok(basename(value.resource.fsPath)); if (['examples', 'other'].indexOf(basename(value.resource.fsPath)) >= 0) { assert.ok(value.isDirectory); + assert.ok(value.mtime! > 0); + assert.ok(value.ctime! > 0); } else if (basename(value.resource.fsPath) === 'index.html') { assert.ok(!value.isDirectory); assert.ok(!value.children); + assert.ok(value.mtime! > 0); + assert.ok(value.ctime! > 0); } else if (basename(value.resource.fsPath) === 'site.css') { assert.ok(!value.isDirectory); assert.ok(!value.children); + assert.ok(value.mtime! > 0); + assert.ok(value.ctime! > 0); } else { assert.ok(!'Unexpected value ' + basename(value.resource.fsPath)); } }); }); + test('resolve - directory with resolveTo', async () => { + const resolved = await service.resolve(URI.file(testDir), { resolveTo: [URI.file(join(testDir, 'deep'))] }); + assert.equal(resolved.children!.length, 8); + + const deep = (getByName(resolved, 'deep')!); + assert.equal(deep.children!.length, 4); + }); + test('resolve - directory - resolveTo single directory', async () => { const resolverFixturesPath = getPathFromAmdModule(require, './fixtures/resolver'); const result = await service.resolve(URI.file(resolverFixturesPath), { resolveTo: [URI.file(join(resolverFixturesPath, 'other/deep'))] }); @@ -1458,15 +1493,15 @@ suite('Disk File Service', function () { } test('createFile', async () => { - assertCreateFile(contents => VSBuffer.fromString(contents)); + return assertCreateFile(contents => VSBuffer.fromString(contents)); }); test('createFile (readable)', async () => { - assertCreateFile(contents => bufferToReadable(VSBuffer.fromString(contents))); + return assertCreateFile(contents => bufferToReadable(VSBuffer.fromString(contents))); }); test('createFile (stream)', async () => { - assertCreateFile(contents => bufferToStream(VSBuffer.fromString(contents))); + return assertCreateFile(contents => bufferToStream(VSBuffer.fromString(contents))); }); async function assertCreateFile(converter: (content: string) => VSBuffer | VSBufferReadable | VSBufferReadableStream): Promise { diff --git a/src/vs/platform/instantiation/common/instantiationService.ts b/src/vs/platform/instantiation/common/instantiationService.ts index 44be0d24797..f4b681204c8 100644 --- a/src/vs/platform/instantiation/common/instantiationService.ts +++ b/src/vs/platform/instantiation/common/instantiationService.ts @@ -157,7 +157,7 @@ export class InstantiationService implements IInstantiationService { graph.lookupOrInsertNode(item); // a weak but working heuristic for cycle checks - if (cycleCount++ > 100) { + if (cycleCount++ > 150) { throw new CyclicDependencyError(graph); } diff --git a/src/vs/platform/opener/common/opener.ts b/src/vs/platform/opener/common/opener.ts index 70377fcb3da..3b60521677a 100644 --- a/src/vs/platform/opener/common/opener.ts +++ b/src/vs/platform/opener/common/opener.ts @@ -28,11 +28,21 @@ type OpenExternalOptions = { readonly openExternal?: boolean; readonly allowTunn export type OpenOptions = OpenInternalOptions & OpenExternalOptions; +export type ResolveExternalUriOptions = { readonly allowTunneling?: boolean }; + +export interface IResolvedExternalUri extends IDisposable { + resolved: URI; +} + export interface IOpener { open(resource: URI, options?: OpenInternalOptions): Promise; open(resource: URI, options?: OpenExternalOptions): Promise; } +export interface IExternalOpener { + openExternal(href: string): Promise; +} + export interface IValidator { shouldOpen(resource: URI): Promise; } @@ -61,6 +71,12 @@ export interface IOpenerService { */ registerExternalUriResolver(resolver: IExternalUriResolver): IDisposable; + /** + * Sets the handler for opening externally. If not provided, + * a default handler will be used. + */ + setExternalOpener(opener: IExternalOpener): void; + /** * Opens a resource, like a webaddress, a document uri, or executes command. * @@ -70,7 +86,10 @@ export interface IOpenerService { open(resource: URI, options?: OpenInternalOptions): Promise; open(resource: URI, options?: OpenExternalOptions): Promise; - resolveExternalUri(resource: URI, options?: { readonly allowTunneling?: boolean }): Promise<{ resolved: URI, dispose(): void }>; + /** + * Resolve a resource to its external form. + */ + resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise; } export const NullOpenerService: IOpenerService = Object.freeze({ @@ -78,6 +97,7 @@ export const NullOpenerService: IOpenerService = Object.freeze({ registerOpener() { return Disposable.None; }, registerValidator() { return Disposable.None; }, registerExternalUriResolver() { return Disposable.None; }, - open() { return Promise.resolve(false); }, + setExternalOpener() { }, + async open() { return false; }, async resolveExternalUri(uri: URI) { return { resolved: uri, dispose() { } }; }, }); diff --git a/src/vs/platform/request/node/proxy.ts b/src/vs/platform/request/node/proxy.ts index 116f7e0c428..30b5bc29a9a 100644 --- a/src/vs/platform/request/node/proxy.ts +++ b/src/vs/platform/request/node/proxy.ts @@ -39,7 +39,7 @@ export async function getProxyAgent(rawRequestURL: string, options: IOptions = { const opts = { host: proxyEndpoint.hostname || '', - port: Number(proxyEndpoint.port), + port: proxyEndpoint.port || (proxyEndpoint.protocol === 'https' ? '443' : '80'), auth: proxyEndpoint.auth, rejectUnauthorized: isBoolean(options.strictSSL) ? options.strictSSL : true }; diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 89c695d2dee..4c3093b823d 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -103,7 +103,7 @@ class ColorRegistry implements IColorRegistry { public registerColor(id: string, defaults: ColorDefaults | null, description: string, needsTransparency = false, deprecationMessage?: string): ColorIdentifier { let colorContribution: ColorContribution = { id, description, defaults, needsTransparency, deprecationMessage }; this.colorsById[id] = colorContribution; - let propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', defaultSnippets: [{ body: '#ff0000' }] }; + let propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', defaultSnippets: [{ body: '${1:#ff0000}' }] }; if (deprecationMessage) { propertySchema.deprecationMessage = deprecationMessage; } diff --git a/src/vs/platform/theme/common/themeService.ts b/src/vs/platform/theme/common/themeService.ts index 42e93300a85..8117fd486a3 100644 --- a/src/vs/platform/theme/common/themeService.ts +++ b/src/vs/platform/theme/common/themeService.ts @@ -10,6 +10,7 @@ import * as platform from 'vs/platform/registry/common/platform'; import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry'; import { Event, Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { TokenStyle, TokenClassification, ProbeScope } from 'vs/platform/theme/common/tokenClassificationRegistry'; export const IThemeService = createDecorator('themeService'); @@ -59,6 +60,10 @@ export interface ITheme { * default color will be used. */ defines(color: ColorIdentifier): boolean; + + getTokenStyle(classification: TokenClassification, useDefault?: boolean): TokenStyle | undefined; + + resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined; } export interface IIconTheme { diff --git a/src/vs/platform/theme/common/tokenClassificationRegistry.ts b/src/vs/platform/theme/common/tokenClassificationRegistry.ts new file mode 100644 index 00000000000..2ec489ae46f --- /dev/null +++ b/src/vs/platform/theme/common/tokenClassificationRegistry.ts @@ -0,0 +1,478 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as platform from 'vs/platform/registry/common/platform'; +import { Color } from 'vs/base/common/color'; +import { ITheme } from 'vs/platform/theme/common/themeService'; +import * as nls from 'vs/nls'; +import { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; + +// ------ API types + +export const TOKEN_TYPE_WILDCARD = '*'; +export const TOKEN_TYPE_WILDCARD_NUM = -1; + +// qualified string [type|*](.modifier)* +export type TokenClassificationString = string; + +export interface TokenClassification { + type: number; + modifiers: number; +} + +export interface TokenTypeOrModifierContribution { + readonly num: number; + readonly id: string; + readonly description: string; + readonly deprecationMessage: string | undefined; +} + + +export interface TokenStyleData { + foreground?: Color; + bold?: boolean; + underline?: boolean; + italic?: boolean; +} + +export class TokenStyle implements Readonly { + constructor( + public readonly foreground?: Color, + public readonly bold?: boolean, + public readonly underline?: boolean, + public readonly italic?: boolean, + ) { + } +} + +export namespace TokenStyle { + export function fromData(data: { foreground?: Color, bold?: boolean, underline?: boolean, italic?: boolean }) { + return new TokenStyle(data.foreground, data.bold, data.underline, data.italic); + } +} + +export type ProbeScope = string[]; + +export interface TokenStyleFunction { + (theme: ITheme): TokenStyle | undefined; +} + +export interface TokenStyleDefaults { + scopesToProbe: ProbeScope[]; + light: TokenStyleValue | null; + dark: TokenStyleValue | null; + hc: TokenStyleValue | null; +} + +export interface TokenStylingDefaultRule { + classification: TokenClassification; + matchScore: number; + defaults: TokenStyleDefaults; +} + +export interface TokenStylingRule { + classification: TokenClassification; + matchScore: number; + value: TokenStyle; +} + +/** + * A TokenStyle Value is either a token style literal, or a TokenClassificationString + */ +export type TokenStyleValue = TokenStyle | TokenClassificationString; + +// TokenStyle registry +export const Extensions = { + TokenClassificationContribution: 'base.contributions.tokenClassification' +}; + +export interface ITokenClassificationRegistry { + + readonly onDidChangeSchema: Event; + + /** + * Register a token type to the registry. + * @param id The TokenType id as used in theme description files + * @description the description + */ + registerTokenType(id: string, description: string): void; + + /** + * Register a token modifier to the registry. + * @param id The TokenModifier id as used in theme description files + * @description the description + */ + registerTokenModifier(id: string, description: string): void; + + getTokenClassificationFromString(str: TokenClassificationString): TokenClassification | undefined; + getTokenClassification(type: string, modifiers: string[]): TokenClassification | undefined; + + getTokenStylingRule(classification: TokenClassification, value: TokenStyle): TokenStylingRule; + + /** + * Register a TokenStyle default to the registry. + * @param selector The rule selector + * @param defaults The default values + */ + registerTokenStyleDefault(selector: TokenClassification, defaults: TokenStyleDefaults): void; + + /** + * Deregister a TokenType from the registry. + */ + deregisterTokenType(id: string): void; + + /** + * Deregister a TokenModifier from the registry. + */ + deregisterTokenModifier(id: string): void; + + /** + * Get all TokenType contributions + */ + getTokenTypes(): TokenTypeOrModifierContribution[]; + + /** + * Get all TokenModifier contributions + */ + getTokenModifiers(): TokenTypeOrModifierContribution[]; + + /** + * Resolves a token classification against the given rules and default rules from the registry. + */ + resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[] | undefined, customThemingRules: TokenStylingRule[], theme: ITheme): TokenStyle | undefined; + + /** + * JSON schema for an object to assign styling to token classifications + */ + getTokenStylingSchema(): IJSONSchema; +} + +class TokenClassificationRegistry implements ITokenClassificationRegistry { + + private readonly _onDidChangeSchema = new Emitter(); + readonly onDidChangeSchema: Event = this._onDidChangeSchema.event; + + private currentTypeNumber = 0; + private currentModifierBit = 1; + + private tokenTypeById: { [key: string]: TokenTypeOrModifierContribution }; + private tokenModifierById: { [key: string]: TokenTypeOrModifierContribution }; + + private tokenStylingDefaultRules: TokenStylingDefaultRule[] = []; + + private tokenStylingSchema: IJSONSchema & { properties: IJSONSchemaMap } = { + type: 'object', + properties: {}, + definitions: { + style: { + type: 'object', + description: nls.localize('schema.token.settings', 'Colors and styles for the token.'), + properties: { + foreground: { + type: 'string', + description: nls.localize('schema.token.foreground', 'Foreground color for the token.'), + format: 'color-hex', + default: '#ff0000' + }, + background: { + type: 'string', + deprecationMessage: nls.localize('schema.token.background.warning', 'Token background colors are currently not supported.') + }, + fontStyle: { + type: 'string', + description: nls.localize('schema.token.fontStyle', 'Font style of the rule: \'italic\', \'bold\' or \'underline\', \'-italic\', \'-bold\' or \'-underline\'or a combination. The empty string unsets inherited settings.'), + pattern: '^(\\s*(-?italic|-?bold|-?underline))*\\s*$', + patternErrorMessage: nls.localize('schema.fontStyle.error', 'Font style must be \'italic\', \'bold\' or \'underline\' to set a style or \'-italic\', \'-bold\' or \'-underline\' to unset or a combination. The empty string unsets all styles.'), + defaultSnippets: [{ label: nls.localize('schema.token.fontStyle.none', 'None (clear inherited style)'), bodyText: '""' }, { body: 'italic' }, { body: 'bold' }, { body: 'underline' }, { body: '-italic' }, { body: '-bold' }, { body: '-underline' }, { body: 'italic bold' }, { body: 'italic underline' }, { body: 'bold underline' }, { body: 'italic bold underline' }] + } + }, + additionalProperties: false, + defaultSnippets: [{ body: { foreground: '${1:#FF0000}', fontStyle: '${2:bold}' } }] + } + } + }; + + constructor() { + this.tokenTypeById = {}; + this.tokenModifierById = {}; + + this.tokenTypeById[TOKEN_TYPE_WILDCARD] = { num: TOKEN_TYPE_WILDCARD_NUM, id: TOKEN_TYPE_WILDCARD, description: '', deprecationMessage: undefined }; + } + + public registerTokenType(id: string, description: string, deprecationMessage?: string): void { + const num = this.currentTypeNumber++; + let tokenStyleContribution: TokenTypeOrModifierContribution = { num, id, description, deprecationMessage }; + this.tokenTypeById[id] = tokenStyleContribution; + + this.tokenStylingSchema.properties[id] = getStylingSchemeEntry(description, deprecationMessage); + } + + public registerTokenModifier(id: string, description: string, deprecationMessage?: string): void { + const num = this.currentModifierBit; + this.currentModifierBit = this.currentModifierBit * 2; + let tokenStyleContribution: TokenTypeOrModifierContribution = { num, id, description, deprecationMessage }; + this.tokenModifierById[id] = tokenStyleContribution; + + this.tokenStylingSchema.properties[`*.${id}`] = getStylingSchemeEntry(description, deprecationMessage); + } + + public getTokenClassification(type: string, modifiers: string[]): TokenClassification | undefined { + const tokenTypeDesc = this.tokenTypeById[type]; + if (!tokenTypeDesc) { + return undefined; + } + let allModifierBits = 0; + for (const modifier of modifiers) { + const tokenModifierDesc = this.tokenModifierById[modifier]; + if (tokenModifierDesc) { + allModifierBits |= tokenModifierDesc.num; + } + } + return { type: tokenTypeDesc.num, modifiers: allModifierBits }; + } + + public getTokenClassificationFromString(str: TokenClassificationString): TokenClassification | undefined { + const parts = str.split('.'); + const type = parts.shift(); + if (type) { + return this.getTokenClassification(type, parts); + } + return undefined; + } + + public getTokenStylingRule(classification: TokenClassification, value: TokenStyle): TokenStylingRule { + return { classification, matchScore: getTokenStylingScore(classification), value }; + } + + public registerTokenStyleDefault(classification: TokenClassification, defaults: TokenStyleDefaults): void { + this.tokenStylingDefaultRules.push({ classification, matchScore: getTokenStylingScore(classification), defaults }); + } + + public deregisterTokenType(id: string): void { + delete this.tokenTypeById[id]; + delete this.tokenStylingSchema.properties[id]; + } + + public deregisterTokenModifier(id: string): void { + delete this.tokenModifierById[id]; + delete this.tokenStylingSchema.properties[`*.${id}`]; + } + + public getTokenTypes(): TokenTypeOrModifierContribution[] { + return Object.keys(this.tokenTypeById).map(id => this.tokenTypeById[id]); + } + + public getTokenModifiers(): TokenTypeOrModifierContribution[] { + return Object.keys(this.tokenModifierById).map(id => this.tokenModifierById[id]); + } + + public resolveTokenStyle(classification: TokenClassification, themingRules: TokenStylingRule[] | undefined, customThemingRules: TokenStylingRule[], theme: ITheme): TokenStyle | undefined { + let result: any = { + foreground: undefined, + bold: undefined, + underline: undefined, + italic: undefined + }; + let score = { + foreground: -1, + bold: -1, + underline: -1, + italic: -1 + }; + + function _processStyle(matchScore: number, style: TokenStyle) { + if (style.foreground && score.foreground <= matchScore) { + score.foreground = matchScore; + result.foreground = style.foreground; + } + for (let p of ['bold', 'underline', 'italic']) { + const property = p as keyof TokenStyle; + const info = style[property]; + if (info !== undefined) { + if (score[property] <= matchScore) { + score[property] = matchScore; + result[property] = info; + } + } + } + } + if (themingRules === undefined) { + for (const rule of this.tokenStylingDefaultRules) { + const matchScore = match(rule, classification); + if (matchScore >= 0) { + let style = theme.resolveScopes(rule.defaults.scopesToProbe); + if (!style) { + style = this.resolveTokenStyleValue(rule.defaults[theme.type], theme); + } + if (style) { + _processStyle(matchScore, style); + } + } + } + } else { + for (const rule of themingRules) { + const matchScore = match(rule, classification); + if (matchScore >= 0) { + _processStyle(matchScore, rule.value); + } + } + } + for (const rule of customThemingRules) { + const matchScore = match(rule, classification); + if (matchScore >= 0) { + _processStyle(matchScore, rule.value); + } + } + return TokenStyle.fromData(result); + } + + /** + * @param tokenStyleValue Resolve a tokenStyleValue in the context of a theme + */ + private resolveTokenStyleValue(tokenStyleValue: TokenStyleValue | null, theme: ITheme): TokenStyle | undefined { + if (tokenStyleValue === null) { + return undefined; + } else if (typeof tokenStyleValue === 'string') { + const classification = this.getTokenClassificationFromString(tokenStyleValue); + if (classification) { + return theme.getTokenStyle(classification); + } + } else if (typeof tokenStyleValue === 'object') { + return tokenStyleValue; + } + return undefined; + } + + public getTokenStylingSchema(): IJSONSchema { + return this.tokenStylingSchema; + } + + + public toString() { + let sorter = (a: string, b: string) => { + let cat1 = a.indexOf('.') === -1 ? 0 : 1; + let cat2 = b.indexOf('.') === -1 ? 0 : 1; + if (cat1 !== cat2) { + return cat1 - cat2; + } + return a.localeCompare(b); + }; + + return Object.keys(this.tokenTypeById).sort(sorter).map(k => `- \`${k}\`: ${this.tokenTypeById[k].description}`).join('\n'); + } + +} + +function match(themeSelector: TokenStylingRule | TokenStylingDefaultRule, classification: TokenClassification): number { + const selectorType = themeSelector.classification.type; + if (selectorType !== TOKEN_TYPE_WILDCARD_NUM && selectorType !== classification.type) { + return -1; + } + const selectorModifier = themeSelector.classification.modifiers; + if ((classification.modifiers & selectorModifier) !== selectorModifier) { + return -1; + } + return themeSelector.matchScore; +} + + +const tokenClassificationRegistry = new TokenClassificationRegistry(); +platform.Registry.add(Extensions.TokenClassificationContribution, tokenClassificationRegistry); + +export function registerTokenType(id: string, description: string, scopesToProbe: ProbeScope[] = [], extendsTC: string | null = null, deprecationMessage?: string): string { + tokenClassificationRegistry.registerTokenType(id, description, deprecationMessage); + + if (scopesToProbe || extendsTC) { + const classification = tokenClassificationRegistry.getTokenClassification(id, []); + tokenClassificationRegistry.registerTokenStyleDefault(classification!, { scopesToProbe, light: extendsTC, dark: extendsTC, hc: extendsTC }); + } + return id; +} + +export function registerTokenModifier(id: string, description: string, deprecationMessage?: string): string { + tokenClassificationRegistry.registerTokenModifier(id, description, deprecationMessage); + return id; +} + +export function getTokenClassificationRegistry(): ITokenClassificationRegistry { + return tokenClassificationRegistry; +} + +export const comments = registerTokenType('comments', nls.localize('comments', "Style for comments."), [['comment']]); +export const strings = registerTokenType('strings', nls.localize('strings', "Style for strings."), [['string']]); +export const keywords = registerTokenType('keywords', nls.localize('keywords', "Style for keywords."), [['keyword.control']]); +export const numbers = registerTokenType('numbers', nls.localize('numbers', "Style for numbers."), [['constant.numeric']]); +export const regexp = registerTokenType('regexp', nls.localize('regexp', "Style for expressions."), [['constant.regexp']]); +export const operators = registerTokenType('operators', nls.localize('operator', "Style for operators."), [['keyword.operator']]); + +export const namespaces = registerTokenType('namespaces', nls.localize('namespace', "Style for namespaces."), [['entity.name.namespace']]); + +export const types = registerTokenType('types', nls.localize('types', "Style for types."), [['entity.name.type'], ['entity.name.class'], ['support.type'], ['support.class']]); +export const structs = registerTokenType('structs', nls.localize('struct', "Style for structs."), [['storage.type.struct']], types); +export const classes = registerTokenType('classes', nls.localize('class', "Style for classes."), [['entity.name.class']], types); +export const interfaces = registerTokenType('interfaces', nls.localize('interface', "Style for interfaces."), undefined, types); +export const enums = registerTokenType('enums', nls.localize('enum', "Style for enums."), undefined, types); +export const parameterTypes = registerTokenType('parameterTypes', nls.localize('parameterType', "Style for parameter types."), undefined, types); + +export const functions = registerTokenType('functions', nls.localize('functions', "Style for functions"), [['entity.name.function'], ['support.function']]); +export const macros = registerTokenType('macros', nls.localize('macro', "Style for macros."), undefined, functions); + +export const variables = registerTokenType('variables', nls.localize('variables', "Style for variables."), [['variable'], ['entity.name.variable']]); +export const constants = registerTokenType('constants', nls.localize('constants', "Style for constants."), undefined, variables); +export const parameters = registerTokenType('parameters', nls.localize('parameters', "Style for parameters."), undefined, variables); +export const property = registerTokenType('properties', nls.localize('properties', "Style for properties."), undefined, variables); + +export const labels = registerTokenType('labels', nls.localize('labels', "Style for labels. "), undefined); + +export const m_declaration = registerTokenModifier('declaration', nls.localize('declaration', "Style for all symbol declarations."), undefined); +export const m_documentation = registerTokenModifier('documentation', nls.localize('documentation', "Style to use for references in documentation."), undefined); +export const m_member = registerTokenModifier('member', nls.localize('member', "Style to use for member functions, variables (fields) and types."), undefined); +export const m_static = registerTokenModifier('static', nls.localize('static', "Style to use for symbols that are static."), undefined); +export const m_abstract = registerTokenModifier('abstract', nls.localize('abstract', "Style to use for symbols that are abstract."), undefined); +export const m_deprecated = registerTokenModifier('deprecated', nls.localize('deprecated', "Style to use for symbols that are deprecated."), undefined); +export const m_modification = registerTokenModifier('modification', nls.localize('modification', "Style to use for write accesses."), undefined); +export const m_async = registerTokenModifier('async', nls.localize('async', "Style to use for symbols that are async."), undefined); + +function bitCount(u: number) { + // https://blogs.msdn.microsoft.com/jeuge/2005/06/08/bit-fiddling-3/ + const uCount = u - ((u >> 1) & 0o33333333333) - ((u >> 2) & 0o11111111111); + return ((uCount + (uCount >> 3)) & 0o30707070707) % 63; +} + +function getTokenStylingScore(classification: TokenClassification) { + return bitCount(classification.modifiers) + ((classification.type !== TOKEN_TYPE_WILDCARD_NUM) ? 1 : 0); +} + +function getStylingSchemeEntry(description: string, deprecationMessage?: string): IJSONSchema { + return { + description, + deprecationMessage, + defaultSnippets: [{ body: '${1:#ff0000}' }], + anyOf: [ + { + type: 'string', + format: 'color-hex' + }, + { + $ref: '#definitions/style' + } + ] + }; +} + +export const tokenStylingSchemaId = 'vscode://schemas/token-styling'; + +let schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution); +schemaRegistry.registerSchema(tokenStylingSchemaId, tokenClassificationRegistry.getTokenStylingSchema()); + +const delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(tokenStylingSchemaId), 200); +tokenClassificationRegistry.onDidChangeSchema(() => { + if (!delayer.isScheduled()) { + delayer.schedule(); + } +}); diff --git a/src/vs/platform/theme/test/common/testThemeService.ts b/src/vs/platform/theme/test/common/testThemeService.ts index fd49d393a34..b9279dc39ee 100644 --- a/src/vs/platform/theme/test/common/testThemeService.ts +++ b/src/vs/platform/theme/test/common/testThemeService.ts @@ -6,6 +6,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IThemeService, ITheme, DARK, IIconTheme } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; +import { TokenStyle, TokenClassification, ProbeScope } from 'vs/platform/theme/common/tokenClassificationRegistry'; export class TestTheme implements ITheme { @@ -23,6 +24,14 @@ export class TestTheme implements ITheme { defines(color: string): boolean { throw new Error('Method not implemented.'); } + + getTokenStyle(classification: TokenClassification, useDefault?: boolean | undefined): TokenStyle | undefined { + throw new Error('Method not implemented.'); + } + + resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined { + throw new Error('Method not implemented.'); + } } export class TestIconTheme implements IIconTheme { diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 25d57792ec3..b1f5ccc6280 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -128,7 +128,7 @@ declare module 'vscode' { readonly isDirty: boolean; /** - * `true` if the document have been closed. A closed document isn't synchronized anymore + * `true` if the document has been closed. A closed document isn't synchronized anymore * and won't be re-used when the same resource is opened again. */ readonly isClosed: boolean; @@ -5986,6 +5986,9 @@ declare module 'vscode' { /** * Create a new directory (Note, that new files are created via `write`-calls). * + * *Note* that missing directories are created automatically, e.g this call has + * `mkdirp` semantics. + * * @param uri The uri of the new folder. */ createDirectory(uri: Uri): Thenable; diff --git a/src/vs/workbench/api/browser/mainThreadDialogs.ts b/src/vs/workbench/api/browser/mainThreadDialogs.ts index b4e38d56698..94ab09b7eba 100644 --- a/src/vs/workbench/api/browser/mainThreadDialogs.ts +++ b/src/vs/workbench/api/browser/mainThreadDialogs.ts @@ -33,11 +33,11 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { private static _convertOpenOptions(options: MainThreadDialogOpenOptions): IOpenDialogOptions { const result: IOpenDialogOptions = { - openLabel: options.openLabel, + openLabel: options.openLabel || undefined, canSelectFiles: options.canSelectFiles || (!options.canSelectFiles && !options.canSelectFolders), canSelectFolders: options.canSelectFolders, canSelectMany: options.canSelectMany, - defaultUri: URI.revive(options.defaultUri) + defaultUri: options.defaultUri ? URI.revive(options.defaultUri) : undefined }; if (options.filters) { result.filters = []; @@ -48,8 +48,8 @@ export class MainThreadDialogs implements MainThreadDiaglogsShape { private static _convertSaveOptions(options: MainThreadDialogSaveOptions): ISaveDialogOptions { const result: ISaveDialogOptions = { - defaultUri: URI.revive(options.defaultUri), - saveLabel: options.saveLabel + defaultUri: options.defaultUri ? URI.revive(options.defaultUri) : undefined, + saveLabel: options.saveLabel || undefined }; if (options.filters) { result.filters = []; diff --git a/src/vs/workbench/api/browser/mainThreadDocuments.ts b/src/vs/workbench/api/browser/mainThreadDocuments.ts index 05eb4662f39..2b743a9484f 100644 --- a/src/vs/workbench/api/browser/mainThreadDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadDocuments.ts @@ -233,7 +233,7 @@ export class MainThreadDocuments implements MainThreadDocumentsShape { initialValue, useResourcePath: Boolean(resource && resource.path) }).then(model => { - const resource = model.getResource(); + const resource = model.resource; if (!this._modelIsSynced.has(resource.toString())) { throw new Error(`expected URI ${resource.toString()} to have come to LIFE`); diff --git a/src/vs/workbench/api/browser/mainThreadFileSystem.ts b/src/vs/workbench/api/browser/mainThreadFileSystem.ts index 3407a420ca7..4a26a90cd76 100644 --- a/src/vs/workbench/api/browser/mainThreadFileSystem.ts +++ b/src/vs/workbench/api/browser/mainThreadFileSystem.ts @@ -52,10 +52,10 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { $stat(uri: UriComponents): Promise { return this._fileService.resolve(URI.revive(uri), { resolveMetadata: true }).then(stat => { return { - ctime: 0, + ctime: stat.ctime, mtime: stat.mtime, size: stat.size, - type: MainThreadFileSystem._getFileType(stat) + type: MainThreadFileSystem._asFileType(stat) }; }).catch(MainThreadFileSystem._handleError); } @@ -67,12 +67,22 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape { err.name = FileSystemProviderErrorCode.FileNotADirectory; throw err; } - return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._getFileType(child)] as [string, FileType]); + return !stat.children ? [] : stat.children.map(child => [child.name, MainThreadFileSystem._asFileType(child)] as [string, FileType]); }).catch(MainThreadFileSystem._handleError); } - private static _getFileType(stat: IFileStat): FileType { - return (stat.isDirectory ? FileType.Directory : FileType.File) + (stat.isSymbolicLink ? FileType.SymbolicLink : 0); + private static _asFileType(stat: IFileStat): FileType { + let res = 0; + if (stat.isFile) { + res += FileType.File; + + } else if (stat.isDirectory) { + res += FileType.Directory; + } + if (stat.isSymbolicLink) { + res += FileType.SymbolicLink; + } + return res; } $readFile(uri: UriComponents): Promise { diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 3dff068097e..5fdd5b7c951 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -51,7 +51,7 @@ class TrimWhitespaceParticipant implements ISaveParticipantParticipant { } async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { - if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { + if (this.configurationService.getValue('files.trimTrailingWhitespace', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) { this.doTrimTrailingWhitespace(model.textEditorModel, env.reason === SaveReason.AUTO); } } @@ -113,7 +113,7 @@ export class FinalNewLineParticipant implements ISaveParticipantParticipant { } async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { - if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { + if (this.configurationService.getValue('files.insertFinalNewline', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) { this.doInsertFinalNewLine(model.textEditorModel); } } @@ -147,7 +147,7 @@ export class TrimFinalNewLinesParticipant implements ISaveParticipantParticipant } async participate(model: IResolvedTextFileEditorModel, env: { reason: SaveReason; }): Promise { - if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.getResource() })) { + if (this.configurationService.getValue('files.trimFinalNewlines', { overrideIdentifier: model.textEditorModel.getLanguageIdentifier().language, resource: model.resource })) { this.doTrimFinalNewLines(model.textEditorModel, env.reason === SaveReason.AUTO); } } @@ -257,7 +257,7 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { const model = editorModel.textEditorModel; - const settingsOverrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.getResource() }; + const settingsOverrides = { overrideIdentifier: model.getLanguageIdentifier().language, resource: editorModel.resource }; const setting = this._configurationService.getValue('editor.codeActionsOnSave', settingsOverrides); if (!setting) { return undefined; @@ -343,7 +343,7 @@ class ExtHostSaveParticipant implements ISaveParticipantParticipant { return new Promise((resolve, reject) => { setTimeout(() => reject(localize('timeout.onWillSave', "Aborted onWillSaveTextDocument-event after 1750ms")), 1750); - this._proxy.$participateInSave(editorModel.getResource(), env.reason).then(values => { + this._proxy.$participateInSave(editorModel.resource, env.reason).then(values => { if (!values.every(success => success)) { return Promise.reject(new Error('listener failed')); } diff --git a/src/vs/workbench/api/browser/mainThreadTreeViews.ts b/src/vs/workbench/api/browser/mainThreadTreeViews.ts index 031dae4a7f7..58796f182f6 100644 --- a/src/vs/workbench/api/browser/mainThreadTreeViews.ts +++ b/src/vs/workbench/api/browser/mainThreadTreeViews.ts @@ -12,6 +12,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { isUndefinedOrNull, isNumber } from 'vs/base/common/types'; import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; @extHostNamedCustomer(MainContext.MainThreadTreeViews) export class MainThreadTreeViews extends Disposable implements MainThreadTreeViewsShape { @@ -23,13 +24,16 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie extHostContext: IExtHostContext, @IViewsService private readonly viewsService: IViewsService, @INotificationService private readonly notificationService: INotificationService, - @IExtensionService private readonly extensionService: IExtensionService + @IExtensionService private readonly extensionService: IExtensionService, + @ILogService private readonly logService: ILogService ) { super(); this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTreeViews); } $registerTreeViewDataProvider(treeViewId: string, options: { showCollapseAll: boolean, canSelectMany: boolean }): void { + this.logService.trace('MainThreadTreeViews#$registerTreeViewDataProvider', treeViewId, options); + this.extensionService.whenInstalledExtensionsRegistered().then(() => { const dataProvider = new TreeViewDataProvider(treeViewId, this._proxy, this.notificationService); this._dataProviders.set(treeViewId, dataProvider); @@ -49,6 +53,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } $reveal(treeViewId: string, item: ITreeItem, parentChain: ITreeItem[], options: IRevealOptions): Promise { + this.logService.trace('MainThreadTreeViews#$reveal', treeViewId, item, parentChain, options); + return this.viewsService.openView(treeViewId, options.focus) .then(() => { const viewer = this.getTreeView(treeViewId); @@ -60,6 +66,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } $refresh(treeViewId: string, itemsToRefreshByHandle: { [treeItemHandle: string]: ITreeItem }): Promise { + this.logService.trace('MainThreadTreeViews#$refresh', treeViewId, itemsToRefreshByHandle); + const viewer = this.getTreeView(treeViewId); const dataProvider = this._dataProviders.get(treeViewId); if (viewer && dataProvider) { @@ -70,6 +78,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } $setMessage(treeViewId: string, message: string): void { + this.logService.trace('MainThreadTreeViews#$setMessage', treeViewId, message); + const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.message = message; @@ -77,6 +87,8 @@ export class MainThreadTreeViews extends Disposable implements MainThreadTreeVie } $setTitle(treeViewId: string, title: string): void { + this.logService.trace('MainThreadTreeViews#$setTitle', treeViewId, title); + const viewer = this.getTreeView(treeViewId); if (viewer) { viewer.title = title; diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index e578e636d44..26ef1db530a 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -113,7 +113,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors)); const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService)); const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment)); - const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol)); + const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService)); const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService)); const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures)); const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostDocumentsAndEditors)); @@ -130,7 +130,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I // Other instances const extHostClipboard = new ExtHostClipboard(rpcProtocol); - const extHostMessageService = new ExtHostMessageService(rpcProtocol); + const extHostMessageService = new ExtHostMessageService(rpcProtocol, extHostLogService); const extHostDialogs = new ExtHostDialogs(rpcProtocol); const extHostStatusBar = new ExtHostStatusBar(rpcProtocol); const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments); @@ -149,7 +149,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I let done = (!extension.isUnderDevelopment); function informOnce(selector: vscode.DocumentSelector) { if (!done) { - console.info(`Extension '${extension.identifier.value}' uses a document selector without scheme. Learn more about this: https://go.microsoft.com/fwlink/?linkid=872305`); + extHostLogService.info(`Extension '${extension.identifier.value}' uses a document selector without scheme. Learn more about this: https://go.microsoft.com/fwlink/?linkid=872305`); done = true; } } @@ -180,7 +180,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostCommands.registerCommand(true, id, (...args: any[]): any => { const activeTextEditor = extHostEditors.getActiveTextEditor(); if (!activeTextEditor) { - console.warn('Cannot execute ' + id + ' because there is no active text editor.'); + extHostLogService.warn('Cannot execute ' + id + ' because there is no active text editor.'); return undefined; } @@ -190,10 +190,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I }).then((result) => { if (!result) { - console.warn('Edits from command ' + id + ' were not applied.'); + extHostLogService.warn('Edits from command ' + id + ' were not applied.'); } }, (err) => { - console.warn('An error occurred while running command ' + id, err); + extHostLogService.warn('An error occurred while running command ' + id, err); }); }); }, @@ -202,7 +202,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostCommands.registerCommand(true, id, async (...args: any[]): Promise => { const activeTextEditor = extHostEditors.getActiveTextEditor(); if (!activeTextEditor) { - console.warn('Cannot execute ' + id + ' because there is no active text editor.'); + extHostLogService.warn('Cannot execute ' + id + ' because there is no active text editor.'); return undefined; } diff --git a/src/vs/workbench/api/common/extHostConfiguration.ts b/src/vs/workbench/api/common/extHostConfiguration.ts index 44b064059fa..9acade4b04c 100644 --- a/src/vs/workbench/api/common/extHostConfiguration.ts +++ b/src/vs/workbench/api/common/extHostConfiguration.ts @@ -20,6 +20,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { Barrier } from 'vs/base/common/async'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { ILogService } from 'vs/platform/log/common/log'; function lookUp(tree: any, key: string) { if (key) { @@ -45,16 +46,19 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { readonly _serviceBrand: undefined; private readonly _proxy: MainThreadConfigurationShape; + private readonly _logService: ILogService; private readonly _extHostWorkspace: ExtHostWorkspace; private readonly _barrier: Barrier; private _actual: ExtHostConfigProvider | null; constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, - @IExtHostWorkspace extHostWorkspace: IExtHostWorkspace + @IExtHostWorkspace extHostWorkspace: IExtHostWorkspace, + @ILogService logService: ILogService, ) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadConfiguration); this._extHostWorkspace = extHostWorkspace; + this._logService = logService; this._barrier = new Barrier(); this._actual = null; } @@ -64,7 +68,7 @@ export class ExtHostConfiguration implements ExtHostConfigurationShape { } $initializeConfiguration(data: IConfigurationInitData): void { - this._actual = new ExtHostConfigProvider(this._proxy, this._extHostWorkspace, data); + this._actual = new ExtHostConfigProvider(this._proxy, this._extHostWorkspace, data, this._logService); this._barrier.open(); } @@ -80,9 +84,11 @@ export class ExtHostConfigProvider { private readonly _extHostWorkspace: ExtHostWorkspace; private _configurationScopes: Map; private _configuration: Configuration; + private _logService: ILogService; - constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData) { + constructor(proxy: MainThreadConfigurationShape, extHostWorkspace: ExtHostWorkspace, data: IConfigurationInitData, logService: ILogService) { this._proxy = proxy; + this._logService = logService; this._extHostWorkspace = extHostWorkspace; this._configuration = ExtHostConfigProvider.parse(data); this._configurationScopes = this._toMap(data.configurationScopes); @@ -236,13 +242,13 @@ export class ExtHostConfigProvider { const extensionIdText = extensionId ? `[${extensionId.value}] ` : ''; if (ConfigurationScope.RESOURCE === scope) { if (resource === undefined) { - console.warn(`${extensionIdText}Accessing a resource scoped configuration without providing a resource is not expected. To get the effective value for '${key}', provide the URI of a resource or 'null' for any resource.`); + this._logService.warn(`${extensionIdText}Accessing a resource scoped configuration without providing a resource is not expected. To get the effective value for '${key}', provide the URI of a resource or 'null' for any resource.`); } return; } if (ConfigurationScope.WINDOW === scope) { if (resource) { - console.warn(`${extensionIdText}Accessing a window scoped configuration for a resource is not expected. To associate '${key}' to a resource, define its scope to 'resource' in configuration contributions in 'package.json'.`); + this._logService.warn(`${extensionIdText}Accessing a window scoped configuration for a resource is not expected. To associate '${key}' to a resource, define its scope to 'resource' in configuration contributions in 'package.json'.`); } return; } diff --git a/src/vs/workbench/api/common/extHostDecorations.ts b/src/vs/workbench/api/common/extHostDecorations.ts index a0b0612706a..1888766e31f 100644 --- a/src/vs/workbench/api/common/extHostDecorations.ts +++ b/src/vs/workbench/api/common/extHostDecorations.ts @@ -12,6 +12,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { asArray } from 'vs/base/common/arrays'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { ILogService } from 'vs/platform/log/common/log'; interface ProviderData { provider: vscode.DecorationProvider; @@ -28,6 +29,7 @@ export class ExtHostDecorations implements IExtHostDecorations { constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, + @ILogService private readonly _logService: ILogService, ) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadDecorations); } @@ -66,10 +68,10 @@ export class ExtHostDecorations implements IExtHostDecorations { Decoration.validate(data); result[id] = [data.priority, data.bubble, data.title, data.letter, data.color]; } catch (e) { - console.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`); + this._logService.warn(`INVALID decoration from extension '${extensionId.value}': ${e}`); } }, err => { - console.error(err); + this._logService.error(err); }); })).then(() => { diff --git a/src/vs/workbench/api/common/extHostDiagnostics.ts b/src/vs/workbench/api/common/extHostDiagnostics.ts index 1455bb030d8..e0b6831c552 100644 --- a/src/vs/workbench/api/common/extHostDiagnostics.ts +++ b/src/vs/workbench/api/common/extHostDiagnostics.ts @@ -13,6 +13,7 @@ import * as converter from './extHostTypeConverters'; import { mergeSort } from 'vs/base/common/arrays'; import { Event, Emitter } from 'vs/base/common/event'; import { keys } from 'vs/base/common/map'; +import { ILogService } from 'vs/platform/log/common/log'; export class DiagnosticCollection implements vscode.DiagnosticCollection { @@ -253,7 +254,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { readonly onDidChangeDiagnostics: Event = Event.map(Event.debounce(this._onDidChangeDiagnostics.event, ExtHostDiagnostics._debouncer, 50), ExtHostDiagnostics._mapper); - constructor(mainContext: IMainContext) { + constructor(mainContext: IMainContext, @ILogService private readonly _logService: ILogService) { this._proxy = mainContext.getProxy(MainContext.MainThreadDiagnostics); } @@ -266,7 +267,7 @@ export class ExtHostDiagnostics implements ExtHostDiagnosticsShape { } else if (!_collections.has(name)) { owner = name; } else { - console.warn(`DiagnosticCollection with name '${name}' does already exist.`); + this._logService.warn(`DiagnosticCollection with name '${name}' does already exist.`); do { owner = name + ExtHostDiagnostics._idPool++; } while (_collections.has(owner)); diff --git a/src/vs/workbench/api/common/extHostDocumentData.ts b/src/vs/workbench/api/common/extHostDocumentData.ts index 3a166503923..064cbbb0426 100644 --- a/src/vs/workbench/api/common/extHostDocumentData.ts +++ b/src/vs/workbench/api/common/extHostDocumentData.ts @@ -239,8 +239,7 @@ export class ExtHostDocumentData extends MirrorTextModel { } else if (regExpLeadsToEndlessLoop(regexp)) { // use default when custom-regexp is bad - console.warn(`[getWordRangeAtPosition]: ignoring custom regexp '${regexp.source}' because it matches the empty string.`); - regexp = getWordDefinitionFor(this._languageId); + throw new Error(`[getWordRangeAtPosition]: ignoring custom regexp '${regexp.source}' because it matches the empty string.`); } const wordAtText = getWordAtText( diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index ee4043d7860..fb15773114e 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -474,11 +474,11 @@ class NavigateTypeAdapter { private readonly _symbolCache = new Map(); private readonly _resultCache = new Map(); - private readonly _provider: vscode.WorkspaceSymbolProvider; - constructor(provider: vscode.WorkspaceSymbolProvider) { - this._provider = provider; - } + constructor( + private readonly _provider: vscode.WorkspaceSymbolProvider, + private readonly _logService: ILogService + ) { } provideWorkspaceSymbols(search: string, token: CancellationToken): Promise { const result: extHostProtocol.IWorkspaceSymbolsDto = extHostProtocol.IdObject.mixin({ symbols: [] }); @@ -490,7 +490,7 @@ class NavigateTypeAdapter { continue; } if (!item.name) { - console.warn('INVALID SymbolInformation, lacks name', item); + this._logService.warn('INVALID SymbolInformation, lacks name', item); continue; } const symbol = extHostProtocol.IdObject.mixin(typeConvert.WorkspaceSymbol.from(item)); @@ -538,7 +538,8 @@ class RenameAdapter { constructor( private readonly _documents: ExtHostDocuments, - private readonly _provider: vscode.RenameProvider + private readonly _provider: vscode.RenameProvider, + private readonly _logService: ILogService ) { } provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise { @@ -587,7 +588,7 @@ class RenameAdapter { return undefined; } if (range.start.line > pos.line || range.end.line < pos.line) { - console.warn('INVALID rename location: position line must be within range start/end lines'); + this._logService.warn('INVALID rename location: position line must be within range start/end lines'); return undefined; } return { range: typeConvert.Range.from(range), text }; @@ -618,18 +619,15 @@ class SuggestAdapter { return typeof provider.resolveCompletionItem === 'function'; } - private _documents: ExtHostDocuments; - private _commands: CommandsConverter; - private _provider: vscode.CompletionItemProvider; - private _cache = new Cache('CompletionItem'); private _disposables = new Map(); - constructor(documents: ExtHostDocuments, commands: CommandsConverter, provider: vscode.CompletionItemProvider) { - this._documents = documents; - this._commands = commands; - this._provider = provider; - } + constructor( + private readonly _documents: ExtHostDocuments, + private readonly _commands: CommandsConverter, + private readonly _provider: vscode.CompletionItemProvider, + private readonly _logService: ILogService + ) { } provideCompletionItems(resource: URI, position: IPosition, context: modes.CompletionContext, token: CancellationToken): Promise { @@ -712,7 +710,7 @@ class SuggestAdapter { private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: extHostProtocol.ChainedCacheId): extHostProtocol.ISuggestDataDto | undefined { if (typeof item.label !== 'string' || item.label.length === 0) { - console.warn('INVALID text edit -> must have at least a label'); + this._logService.warn('INVALID text edit -> must have at least a label'); return undefined; } @@ -764,7 +762,7 @@ class SuggestAdapter { if (range) { if (Range.isRange(range)) { if (!SuggestAdapter._isValidRangeForCompletion(range, position)) { - console.trace('INVALID range -> must be single line and on the same line'); + this._logService.trace('INVALID range -> must be single line and on the same line'); return undefined; } result[extHostProtocol.ISuggestDataDtoField.range] = typeConvert.Range.from(range); @@ -776,7 +774,7 @@ class SuggestAdapter { || !range.inserting.start.isEqual(range.replacing.start) || !range.replacing.contains(range.inserting) ) { - console.trace('INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range'); + this._logService.trace('INVALID range -> must be single line, on the same line, insert range must be a prefix of replace range'); return undefined; } result[extHostProtocol.ISuggestDataDtoField.range] = { @@ -992,7 +990,8 @@ class SelectionRangeAdapter { constructor( private readonly _documents: ExtHostDocuments, - private readonly _provider: vscode.SelectionRangeProvider + private readonly _provider: vscode.SelectionRangeProvider, + private readonly _logService: ILogService ) { } provideSelectionRanges(resource: URI, pos: IPosition[], token: CancellationToken): Promise { @@ -1004,7 +1003,7 @@ class SelectionRangeAdapter { return []; } if (allProviderRanges.length !== positions.length) { - console.warn('BAD selection ranges, provider must return ranges for each position'); + this._logService.warn('BAD selection ranges, provider must return ranges for each position'); return []; } @@ -1413,7 +1412,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- navigate types registerWorkspaceSymbolProvider(extension: IExtensionDescription, provider: vscode.WorkspaceSymbolProvider): vscode.Disposable { - const handle = this._addNewAdapter(new NavigateTypeAdapter(provider), extension); + const handle = this._addNewAdapter(new NavigateTypeAdapter(provider, this._logService), extension); this._proxy.$registerNavigateTypeSupport(handle); return this._createDisposable(handle); } @@ -1433,7 +1432,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- rename registerRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable { - const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider), extension); + const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider, this._logService), extension); this._proxy.$registerRenameSupport(handle, this._transformDocumentSelector(selector), RenameAdapter.supportsResolving(provider)); return this._createDisposable(handle); } @@ -1449,7 +1448,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- suggestion registerCompletionItemProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable { - const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider), extension); + const handle = this._addNewAdapter(new SuggestAdapter(this._documents, this._commands.converter, provider, this._logService), extension); this._proxy.$registerSuggestSupport(handle, this._transformDocumentSelector(selector), triggerCharacters, SuggestAdapter.supportsResolving(provider), extension.identifier); return this._createDisposable(handle); } @@ -1533,7 +1532,7 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF // --- smart select registerSelectionRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable { - const handle = this._addNewAdapter(new SelectionRangeAdapter(this._documents, provider), extension); + const handle = this._addNewAdapter(new SelectionRangeAdapter(this._documents, provider, this._logService), extension); this._proxy.$registerSelectionRangeProvider(handle, this._transformDocumentSelector(selector)); return this._createDisposable(handle); } diff --git a/src/vs/workbench/api/common/extHostMessageService.ts b/src/vs/workbench/api/common/extHostMessageService.ts index 997ca16271f..31154ab1de9 100644 --- a/src/vs/workbench/api/common/extHostMessageService.ts +++ b/src/vs/workbench/api/common/extHostMessageService.ts @@ -7,6 +7,7 @@ import Severity from 'vs/base/common/severity'; import * as vscode from 'vscode'; import { MainContext, MainThreadMessageServiceShape, MainThreadMessageOptions, IMainContext } from './extHost.protocol'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; function isMessageItem(item: any): item is vscode.MessageItem { return item && item.title; @@ -16,7 +17,10 @@ export class ExtHostMessageService { private _proxy: MainThreadMessageServiceShape; - constructor(mainContext: IMainContext) { + constructor( + mainContext: IMainContext, + @ILogService private readonly _logService: ILogService + ) { this._proxy = mainContext.getProxy(MainContext.MainThreadMessageService); } @@ -45,7 +49,7 @@ export class ExtHostMessageService { let { title, isCloseAffordance } = command; commands.push({ title, isCloseAffordance: !!isCloseAffordance, handle }); } else { - console.warn('Invalid message item:', command); + this._logService.warn('Invalid message item:', command); } } diff --git a/src/vs/workbench/api/common/extHostRequireInterceptor.ts b/src/vs/workbench/api/common/extHostRequireInterceptor.ts index 158239df616..b6f94048fbd 100644 --- a/src/vs/workbench/api/common/extHostRequireInterceptor.ts +++ b/src/vs/workbench/api/common/extHostRequireInterceptor.ts @@ -18,6 +18,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { platform } from 'vs/base/common/process'; +import { ILogService } from 'vs/platform/log/common/log'; interface LoadFunction { @@ -41,7 +42,8 @@ export abstract class RequireInterceptor { @IInstantiationService private readonly _instaService: IInstantiationService, @IExtHostConfiguration private readonly _extHostConfiguration: IExtHostConfiguration, @IExtHostExtensionService private readonly _extHostExtensionService: IExtHostExtensionService, - @IExtHostInitDataService private readonly _initData: IExtHostInitDataService + @IExtHostInitDataService private readonly _initData: IExtHostInitDataService, + @ILogService private readonly _logService: ILogService, ) { this._factories = new Map(); this._alternatives = []; @@ -54,7 +56,7 @@ export abstract class RequireInterceptor { const configProvider = await this._extHostConfiguration.getConfigProvider(); const extensionPaths = await this._extHostExtensionService.getExtensionPathIndex(); - this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider)); + this.register(new VSCodeNodeModuleFactory(this._apiFactory, extensionPaths, this._extensionRegistry, configProvider, this._logService)); this.register(this._instaService.createInstance(KeytarNodeModuleFactory)); if (this._initData.remote.isRemote) { this.register(this._instaService.createInstance(OpenNodeModuleFactory, extensionPaths, this._initData.environment.appUriScheme)); @@ -91,7 +93,8 @@ class VSCodeNodeModuleFactory implements INodeModuleFactory { private readonly _apiFactory: IExtensionApiFactory, private readonly _extensionPaths: TernarySearchTree, private readonly _extensionRegistry: ExtensionDescriptionRegistry, - private readonly _configProvider: ExtHostConfigProvider + private readonly _configProvider: ExtHostConfigProvider, + private readonly _logService: ILogService, ) { } @@ -112,7 +115,7 @@ class VSCodeNodeModuleFactory implements INodeModuleFactory { if (!this._defaultApiImpl) { let extensionPathsPretty = ''; this._extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.identifier.value}\n`); - console.warn(`Could not identify extension for 'vscode' require call from ${parent.fsPath}. These are the extension path mappings: \n${extensionPathsPretty}`); + this._logService.warn(`Could not identify extension for 'vscode' require call from ${parent.fsPath}. These are the extension path mappings: \n${extensionPathsPretty}`); this._defaultApiImpl = this._apiFactory(nullExtensionDescription, this._extensionRegistry, this._configProvider); } return this._defaultApiImpl; diff --git a/src/vs/workbench/api/common/extHostSearch.ts b/src/vs/workbench/api/common/extHostSearch.ts index efc6ca49825..adc7c29d6ec 100644 --- a/src/vs/workbench/api/common/extHostSearch.ts +++ b/src/vs/workbench/api/common/extHostSearch.ts @@ -3,10 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import * as vscode from 'vscode'; -import { ExtHostSearchShape } from '../common/extHost.protocol'; +import { ExtHostSearchShape, MainThreadSearchShape, MainContext } from '../common/extHost.protocol'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { FileSearchManager } from 'vs/workbench/services/search/common/fileSearchManager'; +import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; +import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; +import { ILogService } from 'vs/platform/log/common/log'; +import { IRawFileQuery, ISearchCompleteStats, IFileQuery, IRawTextQuery, IRawQuery, ITextQuery, IFolderQuery } from 'vs/workbench/services/search/common/search'; +import { URI, UriComponents } from 'vs/base/common/uri'; +import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager'; export interface IExtHostSearch extends ExtHostSearchShape { registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider): IDisposable; @@ -14,3 +21,111 @@ export interface IExtHostSearch extends ExtHostSearchShape { } export const IExtHostSearch = createDecorator('IExtHostSearch'); + +export class ExtHostSearch implements ExtHostSearchShape { + + protected readonly _proxy: MainThreadSearchShape = this.extHostRpc.getProxy(MainContext.MainThreadSearch); + protected _handlePool: number = 0; + + private readonly _textSearchProvider = new Map(); + private readonly _textSearchUsedSchemes = new Set(); + private readonly _fileSearchProvider = new Map(); + private readonly _fileSearchUsedSchemes = new Set(); + + private readonly _fileSearchManager = new FileSearchManager(); + + constructor( + @IExtHostRpcService private extHostRpc: IExtHostRpcService, + @IURITransformerService protected _uriTransformer: IURITransformerService, + @ILogService protected _logService: ILogService + ) { } + + protected _transformScheme(scheme: string): string { + return this._uriTransformer.transformOutgoingScheme(scheme); + } + + registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider): IDisposable { + if (this._textSearchUsedSchemes.has(scheme)) { + throw new Error(`a text search provider for the scheme '${scheme}' is already registered`); + } + + this._textSearchUsedSchemes.add(scheme); + const handle = this._handlePool++; + this._textSearchProvider.set(handle, provider); + this._proxy.$registerTextSearchProvider(handle, this._transformScheme(scheme)); + return toDisposable(() => { + this._textSearchUsedSchemes.delete(scheme); + this._textSearchProvider.delete(handle); + this._proxy.$unregisterProvider(handle); + }); + } + + registerFileSearchProvider(scheme: string, provider: vscode.FileSearchProvider): IDisposable { + if (this._fileSearchUsedSchemes.has(scheme)) { + throw new Error(`a file search provider for the scheme '${scheme}' is already registered`); + } + + this._fileSearchUsedSchemes.add(scheme); + const handle = this._handlePool++; + this._fileSearchProvider.set(handle, provider); + this._proxy.$registerFileSearchProvider(handle, this._transformScheme(scheme)); + return toDisposable(() => { + this._fileSearchUsedSchemes.delete(scheme); + this._fileSearchProvider.delete(handle); + this._proxy.$unregisterProvider(handle); + }); + } + + $provideFileSearchResults(handle: number, session: number, rawQuery: IRawFileQuery, token: vscode.CancellationToken): Promise { + const query = reviveQuery(rawQuery); + const provider = this._fileSearchProvider.get(handle); + if (provider) { + return this._fileSearchManager.fileSearch(query, provider, batch => { + this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource)); + }, token); + } else { + throw new Error('unknown provider: ' + handle); + } + } + + $clearCache(cacheKey: string): Promise { + this._fileSearchManager.clearCache(cacheKey); + + return Promise.resolve(undefined); + } + + $provideTextSearchResults(handle: number, session: number, rawQuery: IRawTextQuery, token: vscode.CancellationToken): Promise { + const provider = this._textSearchProvider.get(handle); + if (!provider || !provider.provideTextSearchResults) { + throw new Error(`Unknown provider ${handle}`); + } + + const query = reviveQuery(rawQuery); + const engine = this.createTextSearchManager(query, provider); + return engine.search(progress => this._proxy.$handleTextMatch(handle, session, progress), token); + } + + protected createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider): TextSearchManager { + return new TextSearchManager(query, provider, { + readdir: resource => Promise.resolve([]), // TODO@rob implement + toCanonicalName: encoding => encoding + }); + } +} + +export function reviveQuery(rawQuery: U): U extends IRawTextQuery ? ITextQuery : IFileQuery { + return { + ...rawQuery, // TODO@rob ??? + ...{ + folderQueries: rawQuery.folderQueries && rawQuery.folderQueries.map(reviveFolderQuery), + extraFileResources: rawQuery.extraFileResources && rawQuery.extraFileResources.map(components => URI.revive(components)) + } + }; +} + +function reviveFolderQuery(rawFolderQuery: IFolderQuery): IFolderQuery { + return { + ...rawFolderQuery, + folder: URI.revive(rawFolderQuery.folder) + }; +} diff --git a/src/vs/workbench/api/common/extHostTask.ts b/src/vs/workbench/api/common/extHostTask.ts index 944f6a19619..fc9f83e5d2c 100644 --- a/src/vs/workbench/api/common/extHostTask.ts +++ b/src/vs/workbench/api/common/extHostTask.ts @@ -24,6 +24,7 @@ import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitData import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Schemas } from 'vs/base/common/network'; import * as Platform from 'vs/base/common/platform'; +import { ILogService } from 'vs/platform/log/common/log'; export interface IExtHostTask extends ExtHostTaskShape { @@ -374,6 +375,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { protected readonly _editorService: IExtHostDocumentsAndEditors; protected readonly _configurationService: IExtHostConfiguration; protected readonly _terminalService: IExtHostTerminalService; + protected readonly _logService: ILogService; protected _handleCounter: number; protected _handlers: Map; protected _taskExecutions: Map; @@ -393,7 +395,8 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { @IExtHostWorkspace workspaceService: IExtHostWorkspace, @IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors, @IExtHostConfiguration configurationService: IExtHostConfiguration, - @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService + @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService, + @ILogService logService: ILogService ) { this._proxy = extHostRpc.getProxy(MainContext.MainThreadTask); this._workspaceProvider = workspaceService; @@ -406,6 +409,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape { this._providedCustomExecutions2 = new Map(); this._notProvidedCustomExecutions = new Set(); this._activeCustomExecutions2 = new Map(); + this._logService = logService; } public registerTaskProvider(extension: IExtensionDescription, type: string, provider: vscode.TaskProvider): vscode.Disposable { @@ -661,9 +665,10 @@ export class WorkerExtHostTask extends ExtHostTaskBase { @IExtHostWorkspace workspaceService: IExtHostWorkspace, @IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors, @IExtHostConfiguration configurationService: IExtHostConfiguration, - @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService + @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService, + @ILogService logService: ILogService ) { - super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService); + super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService); if (initData.remote.isRemote && initData.remote.authority) { this.registerTaskSystem(Schemas.vscodeRemote, { scheme: Schemas.vscodeRemote, @@ -696,7 +701,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { if (value) { for (let task of value) { if (!task.definition || !validTypes[task.definition.type]) { - console.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`); + this._logService.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`); } const taskDTO: tasks.TaskDTO | undefined = TaskDTO.from(task, handler.extension); @@ -707,7 +712,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { // is invoked, we have to be able to map it back to our data. taskIdPromises.push(this.addCustomExecution(taskDTO, task, true)); } else { - console.warn('Only custom execution tasks supported.'); + this._logService.warn('Only custom execution tasks supported.'); } } } @@ -721,7 +726,7 @@ export class WorkerExtHostTask extends ExtHostTaskBase { if (CustomExecutionDTO.is(resolvedTaskDTO.execution)) { return resolvedTaskDTO; } else { - console.warn('Only custom execution tasks supported.'); + this._logService.warn('Only custom execution tasks supported.'); } return undefined; } diff --git a/src/vs/workbench/api/common/extHostTreeViews.ts b/src/vs/workbench/api/common/extHostTreeViews.ts index 24b55f765df..15e80858930 100644 --- a/src/vs/workbench/api/common/extHostTreeViews.ts +++ b/src/vs/workbench/api/common/extHostTreeViews.ts @@ -198,7 +198,13 @@ class ExtHostTreeView extends Disposable { private refreshPromise: Promise = Promise.resolve(); private refreshQueue: Promise = Promise.resolve(); - constructor(private viewId: string, options: vscode.TreeViewOptions, private proxy: MainThreadTreeViewsShape, private commands: CommandsConverter, private logService: ILogService, private extension: IExtensionDescription) { + constructor( + private viewId: string, options: vscode.TreeViewOptions, + private proxy: MainThreadTreeViewsShape, + private commands: CommandsConverter, + private logService: ILogService, + private extension: IExtensionDescription + ) { super(); if (extension.contributes && extension.contributes.views) { for (const location in extension.contributes.views) { @@ -250,7 +256,7 @@ class ExtHostTreeView extends Disposable { getChildren(parentHandle: TreeItemHandle | Root): Promise { const parentElement = parentHandle ? this.getExtensionElement(parentHandle) : undefined; if (parentHandle && !parentElement) { - console.error(`No tree item with id \'${parentHandle}\' found.`); + this.logService.error(`No tree item with id \'${parentHandle}\' found.`); return Promise.resolve([]); } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index 158fe11fda7..71bbf302eeb 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1143,8 +1143,8 @@ export class SelectionRange { export class CallHierarchyItem { - _sessionId: string; - _itemId: string; + _sessionId?: string; + _itemId?: string; kind: SymbolKind; name: string; diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 7da97013142..bd3b3b0daf1 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -16,6 +16,7 @@ import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/we import * as vscode from 'vscode'; import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewStateData } from './extHost.protocol'; import { Disposable as VSCodeDisposable } from './extHostTypes'; +import { assertIsDefined } from 'vs/base/common/types'; type IconPath = URI | { light: URI, dark: URI }; @@ -113,7 +114,8 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa readonly _onDidChangeViewStateEmitter = this._register(new Emitter()); public readonly onDidChangeViewState: Event = this._onDidChangeViewStateEmitter.event; - _capabilities: vscode.WebviewEditorCapabilities; + + public _capabilities?: vscode.WebviewEditorCapabilities; constructor( handle: WebviewPanelHandle, @@ -245,7 +247,7 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa } _undoEdits(edits: string[]): void { - this._capabilities.editingCapability?.undoEdits(edits); + assertIsDefined(this._capabilities).editingCapability?.undoEdits(edits); } private assertNotDisposed() { diff --git a/src/vs/workbench/api/node/extHost.services.ts b/src/vs/workbench/api/node/extHost.services.ts index a227d8a67b3..9ae085f5366 100644 --- a/src/vs/workbench/api/node/extHost.services.ts +++ b/src/vs/workbench/api/node/extHost.services.ts @@ -18,7 +18,7 @@ import { ExtHostTask } from 'vs/workbench/api/node/extHostTask'; import { ExtHostDebugService } from 'vs/workbench/api/node/extHostDebugService'; import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch'; -import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; +import { NativeExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; @@ -38,7 +38,7 @@ registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors); registerSingleton(IExtHostTerminalService, ExtHostTerminalService); registerSingleton(IExtHostTask, ExtHostTask); registerSingleton(IExtHostDebugService, ExtHostDebugService); -registerSingleton(IExtHostSearch, ExtHostSearch); +registerSingleton(IExtHostSearch, NativeExtHostSearch); registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths); registerSingleton(IExtHostExtensionService, ExtHostExtensionService); registerSingleton(IExtHostStorage, ExtHostStorage); diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index a5af222b2e6..3082bb70625 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -3,47 +3,37 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancellationToken } from 'vs/base/common/cancellation'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { URI, UriComponents } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; import { ILogService } from 'vs/platform/log/common/log'; -import { IFileQuery, IFolderQuery, IRawFileQuery, IRawQuery, IRawTextQuery, ISearchCompleteStats, ITextQuery, isSerializedFileMatch, ISerializedSearchProgressItem } from 'vs/workbench/services/search/common/search'; -import { FileSearchManager } from 'vs/workbench/services/search/common/fileSearchManager'; +import { IFileQuery, IRawFileQuery, ISearchCompleteStats, isSerializedFileMatch, ISerializedSearchProgressItem, ITextQuery } from 'vs/workbench/services/search/common/search'; import { SearchService } from 'vs/workbench/services/search/node/rawSearchService'; import { RipgrepSearchProvider } from 'vs/workbench/services/search/node/ripgrepSearchProvider'; import { OutputChannel } from 'vs/workbench/services/search/node/ripgrepSearchUtils'; -import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; import * as vscode from 'vscode'; -import { ExtHostSearchShape, MainContext, MainThreadSearchShape } from '../common/extHost.protocol'; import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { ExtHostSearch, reviveQuery } from 'vs/workbench/api/common/extHostSearch'; +import { Schemas } from 'vs/base/common/network'; +import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; +import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager'; -export class ExtHostSearch implements ExtHostSearchShape { +export class NativeExtHostSearch extends ExtHostSearch { - private readonly _proxy: MainThreadSearchShape; - private readonly _textSearchProvider = new Map(); - private readonly _textSearchUsedSchemes = new Set(); - private readonly _fileSearchProvider = new Map(); - private readonly _fileSearchUsedSchemes = new Set(); - private _handlePool: number = 0; + protected _pfs: typeof pfs = pfs; // allow extending for tests private _internalFileSearchHandle: number = -1; private _internalFileSearchProvider: SearchService | null = null; - private _fileSearchManager: FileSearchManager; - - protected _pfs: typeof pfs = pfs; // allow extending for tests - constructor( @IExtHostRpcService extHostRpc: IExtHostRpcService, @IExtHostInitDataService initData: IExtHostInitDataService, - @IURITransformerService private _uriTransformer: IURITransformerService, - @ILogService private _logService: ILogService, + @IURITransformerService _uriTransformer: IURITransformerService, + @ILogService _logService: ILogService, ) { - this._proxy = extHostRpc.getProxy(MainContext.MainThreadSearch); - this._fileSearchManager = new FileSearchManager(); + super(extHostRpc, _uriTransformer, _logService); if (initData.remote.isRemote && initData.remote.authority) { this._registerEHSearchProviders(); @@ -52,8 +42,8 @@ export class ExtHostSearch implements ExtHostSearchShape { private _registerEHSearchProviders(): void { const outputChannel = new OutputChannel(this._logService); - this.registerTextSearchProvider('file', new RipgrepSearchProvider(outputChannel)); - this.registerInternalFileSearchProvider('file', new SearchService()); + this.registerTextSearchProvider(Schemas.file, new RipgrepSearchProvider(outputChannel)); + this.registerInternalFileSearchProvider(Schemas.file, new SearchService()); } private registerInternalFileSearchProvider(scheme: string, provider: SearchService): IDisposable { @@ -67,59 +57,16 @@ export class ExtHostSearch implements ExtHostSearchShape { }); } - private _transformScheme(scheme: string): string { - return this._uriTransformer.transformOutgoingScheme(scheme); - } - - registerTextSearchProvider(scheme: string, provider: vscode.TextSearchProvider): IDisposable { - if (this._textSearchUsedSchemes.has(scheme)) { - throw new Error(`a text search provider for the scheme '${scheme}' is already registered`); - } - - this._textSearchUsedSchemes.add(scheme); - const handle = this._handlePool++; - this._textSearchProvider.set(handle, provider); - this._proxy.$registerTextSearchProvider(handle, this._transformScheme(scheme)); - return toDisposable(() => { - this._textSearchUsedSchemes.delete(scheme); - this._textSearchProvider.delete(handle); - this._proxy.$unregisterProvider(handle); - }); - } - - registerFileSearchProvider(scheme: string, provider: vscode.FileSearchProvider): IDisposable { - if (this._fileSearchUsedSchemes.has(scheme)) { - throw new Error(`a file search provider for the scheme '${scheme}' is already registered`); - } - - this._fileSearchUsedSchemes.add(scheme); - const handle = this._handlePool++; - this._fileSearchProvider.set(handle, provider); - this._proxy.$registerFileSearchProvider(handle, this._transformScheme(scheme)); - return toDisposable(() => { - this._fileSearchUsedSchemes.delete(scheme); - this._fileSearchProvider.delete(handle); - this._proxy.$unregisterProvider(handle); - }); - } - - $provideFileSearchResults(handle: number, session: number, rawQuery: IRawFileQuery, token: CancellationToken): Promise { + $provideFileSearchResults(handle: number, session: number, rawQuery: IRawFileQuery, token: vscode.CancellationToken): Promise { const query = reviveQuery(rawQuery); if (handle === this._internalFileSearchHandle) { return this.doInternalFileSearch(handle, session, query, token); - } else { - const provider = this._fileSearchProvider.get(handle); - if (provider) { - return this._fileSearchManager.fileSearch(query, provider, batch => { - this._proxy.$handleFileMatch(handle, session, batch.map(p => p.resource)); - }, token); - } else { - throw new Error('unknown provider: ' + handle); - } } + + return super.$provideFileSearchResults(handle, session, rawQuery, token); } - private doInternalFileSearch(handle: number, session: number, rawQuery: IFileQuery, token: CancellationToken): Promise { + private doInternalFileSearch(handle: number, session: number, rawQuery: IFileQuery, token: vscode.CancellationToken): Promise { const onResult = (ev: ISerializedSearchProgressItem) => { if (isSerializedFileMatch(ev)) { ev = [ev]; @@ -147,37 +94,11 @@ export class ExtHostSearch implements ExtHostSearchShape { this._internalFileSearchProvider.clearCache(cacheKey); } - this._fileSearchManager.clearCache(cacheKey); - - return Promise.resolve(undefined); + return super.$clearCache(cacheKey); } - $provideTextSearchResults(handle: number, session: number, rawQuery: IRawTextQuery, token: CancellationToken): Promise { - const provider = this._textSearchProvider.get(handle); - if (!provider || !provider.provideTextSearchResults) { - throw new Error(`Unknown provider ${handle}`); - } - - const query = reviveQuery(rawQuery); - const engine = new TextSearchManager(query, provider, this._pfs); - return engine.search(progress => this._proxy.$handleTextMatch(handle, session, progress), token); + protected createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider): TextSearchManager { + return new NativeTextSearchManager(query, provider); } } -function reviveQuery(rawQuery: U): U extends IRawTextQuery ? ITextQuery : IFileQuery { - return { - ...rawQuery, // TODO - ...{ - folderQueries: rawQuery.folderQueries && rawQuery.folderQueries.map(reviveFolderQuery), - extraFileResources: rawQuery.extraFileResources && rawQuery.extraFileResources.map(components => URI.revive(components)) - } - }; -} - -function reviveFolderQuery(rawFolderQuery: IFolderQuery): IFolderQuery { - return { - ...rawFolderQuery, - folder: URI.revive(rawFolderQuery.folder) - }; -} - diff --git a/src/vs/workbench/api/node/extHostStoragePaths.ts b/src/vs/workbench/api/node/extHostStoragePaths.ts index 5a301ad857c..afdd6bf3984 100644 --- a/src/vs/workbench/api/node/extHostStoragePaths.ts +++ b/src/vs/workbench/api/node/extHostStoragePaths.ts @@ -11,6 +11,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { ILogService } from 'vs/platform/log/common/log'; export class ExtensionStoragePaths implements IExtensionStoragePaths { @@ -22,7 +23,10 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths { readonly whenReady: Promise; private _value?: string; - constructor(@IExtHostInitDataService initData: IExtHostInitDataService) { + constructor( + @IExtHostInitDataService initData: IExtHostInitDataService, + @ILogService private readonly _logService: ILogService, + ) { this._workspace = withNullAsUndefined(initData.workspace); this._environment = initData.environment; this.whenReady = this._getOrCreateWorkspaceStoragePath().then(value => this._value = value); @@ -69,7 +73,7 @@ export class ExtensionStoragePaths implements IExtensionStoragePaths { return storagePath; } catch (e) { - console.error(e); + this._logService.error(e); return undefined; } } diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index c7a2ea29e9d..6e1a647067a 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -22,6 +22,7 @@ import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; import { ExtHostTaskBase, TaskHandleDTO, TaskDTO, CustomExecutionDTO, HandlerData } from 'vs/workbench/api/common/extHostTask'; import { Schemas } from 'vs/base/common/network'; +import { ILogService } from 'vs/platform/log/common/log'; export class ExtHostTask extends ExtHostTaskBase { private _variableResolver: ExtHostVariableResolverService | undefined; @@ -32,9 +33,10 @@ export class ExtHostTask extends ExtHostTaskBase { @IExtHostWorkspace workspaceService: IExtHostWorkspace, @IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors, @IExtHostConfiguration configurationService: IExtHostConfiguration, - @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService + @IExtHostTerminalService extHostTerminalService: IExtHostTerminalService, + @ILogService logService: ILogService ) { - super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService); + super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService); if (initData.remote.isRemote && initData.remote.authority) { this.registerTaskSystem(Schemas.vscodeRemote, { scheme: Schemas.vscodeRemote, @@ -71,7 +73,7 @@ export class ExtHostTask extends ExtHostTaskBase { if (value) { for (let task of value) { if (!task.definition || !validTypes[task.definition.type]) { - console.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`); + this._logService.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`); } const taskDTO: tasks.TaskDTO | undefined = TaskDTO.from(task, handler.extension); diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 24ebadeba87..81fd79a40a4 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -747,6 +747,13 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi if (config.silentNotifications) { this.notificationService.setFilter(NotificationsFilter.ERROR); } + this.state.zenMode.transitionDisposables.add(this.configurationService.onDidChangeConfiguration(c => { + const silentNotificationsKey = 'zenMode.silentNotifications'; + if (c.affectsConfiguration(silentNotificationsKey)) { + const filter = this.configurationService.getValue(silentNotificationsKey) ? NotificationsFilter.ERROR : NotificationsFilter.OFF; + this.notificationService.setFilter(filter); + } + })); if (config.centerLayout) { this.centerEditorLayout(true, true); diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index a830603ce58..669ee10f294 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -112,6 +112,8 @@ export abstract class BaseEditor extends Panel implements IEditor { this.createEditor(parent); } + onHide() { } + /** * Called to create the editor in the parent HTMLElement. */ diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index 53b00a24b33..d196daa8517 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -93,7 +93,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { } const [binaryContainer, scrollbar] = assertAllDefined(this.binaryContainer, this.scrollbar); - this.resourceViewerContext = ResourceViewer.show({ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag(), mime: model.getMime() }, binaryContainer, scrollbar, { + this.resourceViewerContext = ResourceViewer.show({ name: model.getName(), resource: model.resource, size: model.getSize(), etag: model.getETag(), mime: model.getMime() }, binaryContainer, scrollbar, { openInternalClb: () => this.handleOpenInternalCallback(input, options), openExternalClb: this.environmentService.configuration.remoteAuthority ? undefined : resource => this.callbacks.openExternal(resource), metadataClb: meta => this.handleMetadataChanged(meta) diff --git a/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts index 3fe6abaef73..432a8fdc546 100644 --- a/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -208,6 +208,7 @@ export class EditorControl extends Disposable { if (controlInstanceContainer) { this.parent.removeChild(controlInstanceContainer); hide(controlInstanceContainer); + this._activeControl.onHide(); } // Indicate to editor control diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index b7ecb1411b0..71ac2878d4e 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/editorstatus'; import * as nls from 'vs/nls'; import { runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; -import { format } from 'vs/base/common/strings'; +import { format, compare } from 'vs/base/common/strings'; import { extname, basename, isEqual } from 'vs/base/common/resources'; import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; @@ -50,6 +50,8 @@ import { Event } from 'vs/base/common/event'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; +import { IMarker, IMarkerService, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers'; +import { find } from 'vs/base/common/arrays'; class SideBySideEditorEncodingSupport implements IEncodingSupport { constructor(private master: IEncodingSupport, private details: IEncodingSupport) { } @@ -282,6 +284,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { private readonly eolElement = this._register(new MutableDisposable()); private readonly modeElement = this._register(new MutableDisposable()); private readonly metadataElement = this._register(new MutableDisposable()); + private readonly currentProblemStatus: ShowCurrentMarkerInStatusbarContribution = this._register(this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarContribution)); private readonly state = new State(); private readonly activeEditorListeners = this._register(new DisposableStore()); @@ -299,7 +302,8 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { @IConfigurationService private readonly configurationService: IConfigurationService, @INotificationService private readonly notificationService: INotificationService, @IAccessibilityService private readonly accessibilityService: IAccessibilityService, - @IStatusbarService private readonly statusbarService: IStatusbarService + @IStatusbarService private readonly statusbarService: IStatusbarService, + @IInstantiationService private readonly instantiationService: IInstantiationService, ) { super(); @@ -577,6 +581,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.onEncodingChange(activeControl, activeCodeEditor); this.onIndentationChange(activeCodeEditor); this.onMetadataChange(activeControl); + this.currentProblemStatus.update(activeCodeEditor); // Dispose old active editor listeners this.activeEditorListeners.clear(); @@ -594,6 +599,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { // Hook Listener for Selection changes this.activeEditorListeners.add(activeCodeEditor.onDidChangeCursorPosition((event: ICursorPositionChangedEvent) => { this.onSelectionChange(activeCodeEditor); + this.currentProblemStatus.update(activeCodeEditor); })); // Hook Listener for mode changes @@ -604,6 +610,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { // Hook Listener for content changes this.activeEditorListeners.add(activeCodeEditor.onDidChangeModelContent((e) => { this.onEOLChange(activeCodeEditor); + this.currentProblemStatus.update(activeCodeEditor); const selections = activeCodeEditor.getSelections(); if (selections) { @@ -824,6 +831,130 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } +class ShowCurrentMarkerInStatusbarContribution extends Disposable { + + private readonly statusBarEntryAccessor: MutableDisposable; + private editor: ICodeEditor | undefined = undefined; + private markers: IMarker[] = []; + private currentMarker: IMarker | null = null; + + constructor( + @IStatusbarService private readonly statusbarService: IStatusbarService, + @IMarkerService private readonly markerService: IMarkerService, + @IConfigurationService private readonly configurationService: IConfigurationService, + ) { + super(); + this.statusBarEntryAccessor = this._register(new MutableDisposable()); + this._register(markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources))); + this._register(Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('problems.showCurrentInStatus'))(() => this.updateStatus())); + } + + update(editor: ICodeEditor | undefined): void { + this.editor = editor; + this.updateStatus(); + } + + private updateStatus(): void { + const previousMarker = this.currentMarker; + this.currentMarker = this.getMarker(); + if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) { + if (this.currentMarker) { + const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0]; + const text = `${this.getType(this.currentMarker)} ${line}`; + if (!this.statusBarEntryAccessor.value) { + this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '' }, 'statusbar.currentProblem', nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); + } + this.statusBarEntryAccessor.value.update({ text }); + } else { + this.statusBarEntryAccessor.clear(); + } + } + } + + private hasToUpdateStatus(previousMarker: IMarker | null, currentMarker: IMarker | null): boolean { + if (!currentMarker) { + return true; + } + if (!previousMarker) { + return true; + } + return IMarkerData.makeKey(previousMarker) !== IMarkerData.makeKey(currentMarker); + } + + private getType(marker: IMarker): string { + switch (marker.severity) { + case MarkerSeverity.Error: return '$(error)'; + case MarkerSeverity.Warning: return '$(warning)'; + case MarkerSeverity.Info: return '$(info)'; + } + return ''; + } + + private getMarker(): IMarker | null { + if (!this.configurationService.getValue('problems.showCurrentInStatus')) { + return null; + } + if (!this.editor) { + return null; + } + const model = this.editor.getModel(); + if (!model) { + return null; + } + const position = this.editor.getPosition(); + if (!position) { + return null; + } + return find(this.markers, marker => Range.containsPosition(marker, position)) || null; + } + + private onMarkerChanged(changedResources: ReadonlyArray): void { + if (!this.editor) { + return; + } + const model = this.editor.getModel(); + if (!model) { + return; + } + if (model && !changedResources.some(r => isEqual(model.uri, r))) { + return; + } + this.updateMarkers(); + } + + private updateMarkers(): void { + if (!this.editor) { + return; + } + const model = this.editor.getModel(); + if (!model) { + return; + } + if (model) { + this.markers = this.markerService.read({ + resource: model.uri, + severities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info + }); + this.markers.sort(compareMarker); + } else { + this.markers = []; + } + this.updateStatus(); + } +} + +function compareMarker(a: IMarker, b: IMarker): number { + let res = compare(a.resource.toString(), b.resource.toString()); + if (res === 0) { + res = MarkerSeverity.compare(a.severity, b.severity); + } + if (res === 0) { + res = Range.compareRangesUsingStarts(a, b); + } + return res; +} + + function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean { if (!codeEditor) { return false; diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index e4d132cc598..8d4f411c71c 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -33,6 +33,7 @@ import { EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * The text editor that leverages the diff text editor for the editing experience. @@ -55,8 +56,9 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor { @ITextFileService textFileService: ITextFileService, @IHostService hostService: IHostService, @IClipboardService private _clipboardService: IClipboardService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } protected getEditorMemento(editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento { diff --git a/src/vs/workbench/browser/parts/editor/textEditor.ts b/src/vs/workbench/browser/parts/editor/textEditor.ts index ab5403342c3..d7042a43310 100644 --- a/src/vs/workbench/browser/parts/editor/textEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textEditor.ts @@ -16,7 +16,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ITextFileService, SaveReason, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { isDiffEditor, isCodeEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -24,6 +24,7 @@ import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'textEditorViewState'; @@ -53,7 +54,8 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { @ITextFileService private readonly _textFileService: ITextFileService, @IEditorService protected editorService: IEditorService, @IEditorGroupsService protected editorGroupService: IEditorGroupsService, - @IHostService private readonly hostService: IHostService + @IHostService private readonly hostService: IHostService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(id, telemetryService, themeService, storageService); @@ -165,7 +167,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor { } private maybeTriggerSaveAll(reason: SaveReason): void { - const mode = this.textFileService.getAutoSaveMode(); + const mode = this.autoSaveConfigurationService.getAutoSaveMode(); // Determine if we need to save all. In case of a window focus change we also save if auto save mode // is configured to be ON_FOCUS_CHANGE (editor focus change) diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 640af28854b..b4e50ce6a8f 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -24,6 +24,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An editor implementation that is capable of showing the contents of resource inputs. Uses @@ -41,9 +42,10 @@ export class AbstractTextResourceEditor extends BaseTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(id, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } getTitle(): string | undefined { @@ -205,8 +207,9 @@ export class TextResourceEditor extends AbstractTextResourceEditor { @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, @IEditorGroupsService editorGroupService: IEditorGroupsService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(TextResourceEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); } } diff --git a/src/vs/workbench/browser/parts/panel/media/ellipsis-dark.svg b/src/vs/workbench/browser/parts/panel/media/ellipsis-dark.svg deleted file mode 100644 index 2c52e359f61..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/ellipsis-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/ellipsis-hc.svg b/src/vs/workbench/browser/parts/panel/media/ellipsis-hc.svg deleted file mode 100644 index 3d7068f6b4c..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/ellipsis-hc.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/ellipsis-light.svg b/src/vs/workbench/browser/parts/panel/media/ellipsis-light.svg deleted file mode 100644 index 883d2722ce3..00000000000 --- a/src/vs/workbench/browser/parts/panel/media/ellipsis-light.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/parts/panel/media/panelpart.css b/src/vs/workbench/browser/parts/panel/media/panelpart.css index 8de6bf60eaf..64af1d21011 100644 --- a/src/vs/workbench/browser/parts/panel/media/panelpart.css +++ b/src/vs/workbench/browser/parts/panel/media/panelpart.css @@ -43,24 +43,14 @@ /** Panel Switcher */ -.monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { - background-image: url('ellipsis-light.svg'); - display: block; - height: 28px; - min-width: 28px; +.monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.codicon-more { + display: flex; + align-items: center; + justify-content: center; margin-left: 0px; margin-right: 0px; - background-size: 16px; - background-repeat: no-repeat; - background-position: center center; -} + color: inherit !important; -.vs-dark .monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { - background-image: url('ellipsis-dark.svg'); -} - -.hc-black .monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { - background-image: url('ellipsis-hc.svg'); } .monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar { @@ -84,8 +74,6 @@ .monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label{ margin-right: 0; - display: flex; - align-items: center; } .monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:last-child { diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index fec32d605bf..4b365e66ae1 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -84,6 +84,7 @@ interface QuickInputUI { onDidTriggerButton: Event; ignoreFocusOut: boolean; keyMods: Writeable; + keyDownSeenSinceShown: boolean; isScreenReaderOptimized(): boolean; show(controller: QuickInput): void; setVisibilities(visibilities: Visibilities): void; @@ -216,6 +217,7 @@ class QuickInput extends Disposable implements IQuickInput { } }), ); + this.ui.keyDownSeenSinceShown = false; this.ui.show(this); this.visible = true; this.update(); @@ -554,6 +556,7 @@ class QuickPick extends QuickInput implements IQuickPi } })); this.visibleDisposables.add(this.ui.inputBox.onKeyDown(event => { + this.ui.keyDownSeenSinceShown = true; switch (event.keyCode) { case KeyCode.DownArrow: this.ui.list.focus('Next'); @@ -652,7 +655,7 @@ class QuickPick extends QuickInput implements IQuickPi private registerQuickNavigation() { return dom.addDisposableListener(this.ui.container, dom.EventType.KEY_UP, e => { - if (this.canSelectMany || !this.quickNavigate) { + if (this.canSelectMany || !this.quickNavigate || !this.ui.keyDownSeenSinceShown) { return; } @@ -699,10 +702,11 @@ class QuickPick extends QuickInput implements IQuickPi } protected update() { - super.update(); if (!this.visible) { return; } + this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); + super.update(); if (this.ui.inputBox.value !== this.value) { this.ui.inputBox.value = this.value; } @@ -763,7 +767,6 @@ class QuickPick extends QuickInput implements IQuickPi this.ui.list.matchOnLabel = this.matchOnLabel; this.ui.setComboboxAccessibility(true); this.ui.inputBox.setAttribute('aria-label', QuickPick.INPUT_BOX_ARIA_LABEL); - this.ui.setVisibilities(this.canSelectMany ? { title: !!this.title || !!this.step, checkAll: true, inputBox: true, visibleCount: true, count: true, ok: true, list: true, message: !!this.validationMessage } : { title: !!this.title || !!this.step, inputBox: true, visibleCount: true, list: true, message: !!this.validationMessage, customButton: this.customButton, ok: this.ok }); } } @@ -857,10 +860,11 @@ class InputBox extends QuickInput implements IInputBox { } protected update() { - super.update(); if (!this.visible) { return; } + this.ui.setVisibilities({ title: !!this.title || !!this.step, inputBox: true, message: true }); + super.update(); if (this.ui.inputBox.value !== this.value) { this.ui.inputBox.value = this.value; } @@ -882,7 +886,6 @@ class InputBox extends QuickInput implements IInputBox { this.ui.message.textContent = this.validationMessage; this.showMessageDecoration(Severity.Error); } - this.ui.setVisibilities({ title: !!this.title || !!this.step, inputBox: true, message: true }); } } @@ -1111,6 +1114,7 @@ export class QuickInputService extends Component implements IQuickInputService { inputBox.setFocus(); })); this._register(dom.addDisposableListener(container, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this.getUI().keyDownSeenSinceShown = true; const event = new StandardKeyboardEvent(e); switch (event.keyCode) { case KeyCode.Enter: @@ -1172,6 +1176,7 @@ export class QuickInputService extends Component implements IQuickInputService { onDidTriggerButton: this.onDidTriggerButtonEmitter.event, ignoreFocusOut: false, keyMods: this.keyMods, + keyDownSeenSinceShown: false, isScreenReaderOptimized: () => this.isScreenReaderOptimized(), show: controller => this.show(controller), hide: () => this.hide(), diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index f49a302fa42..1e62ba48a8a 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -22,7 +22,7 @@ import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlighte import { memoize } from 'vs/base/common/decorators'; import { range } from 'vs/base/common/arrays'; import * as platform from 'vs/base/common/platform'; -import { listFocusBackground, pickerGroupBorder, pickerGroupForeground, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; +import { listFocusBackground, pickerGroupBorder, pickerGroupForeground, activeContrastBorder, listFocusForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; @@ -590,18 +590,21 @@ function compareEntries(elementA: ListElement, elementB: ListElement, lookFor: s } registerThemingParticipant((theme, collector) => { + // Override inactive focus foreground with active focus foreground for single-pick case. + const listInactiveFocusForeground = theme.getColor(listFocusForeground); + if (listInactiveFocusForeground) { + collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { color: ${listInactiveFocusForeground}; }`); + } // Override inactive focus background with active focus background for single-pick case. const listInactiveFocusBackground = theme.getColor(listFocusBackground); if (listInactiveFocusBackground) { collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { background-color: ${listInactiveFocusBackground}; }`); collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused:hover { background-color: ${listInactiveFocusBackground}; }`); } + // dotted instead of solid (as in listWidget.ts) to match QuickOpen const activeContrast = theme.getColor(activeContrastBorder); if (activeContrast) { - collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { border: 1px dotted ${activeContrast}; }`); - collector.addRule(`.quick-input-list .monaco-list .monaco-list-row { border: 1px solid transparent; }`); - collector.addRule(`.quick-input-list .monaco-list .quick-input-list-entry { padding: 0 5px; height: 18px; align-items: center; }`); - collector.addRule(`.quick-input-list .monaco-list .quick-input-list-entry-action-bar { margin-top: 0; }`); + collector.addRule(`.quick-input-list .monaco-list .monaco-list-row.focused { outline: 1px dotted ${activeContrast}; outline-offset: -1px; }`); } const pickerGroupBorderColor = theme.getColor(pickerGroupBorder); if (pickerGroupBorderColor) { diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index 945da6272a8..80aab18b259 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -16,7 +16,7 @@ import { Mode, IEntryRunContext, IAutoFocus, IQuickNavigateConfiguration, IModel import { QuickOpenEntry, QuickOpenModel, QuickOpenEntryGroup, QuickOpenItemAccessorClass } from 'vs/base/parts/quickopen/browser/quickOpenModel'; import { QuickOpenWidget, HideReason } from 'vs/base/parts/quickopen/browser/quickOpenWidget'; import { ContributableActionProvider } from 'vs/workbench/browser/actions'; -import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { Registry } from 'vs/platform/registry/common/platform'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -51,6 +51,7 @@ import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/commo import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const HELP_PREFIX = '?'; @@ -735,7 +736,8 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { @ITextFileService private readonly textFileService: ITextFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @ILabelService labelService: ILabelService, - @IFileService fileService: IFileService + @IFileService fileService: IFileService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(editorService); @@ -753,7 +755,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry { this.description = labelService.getUriLabel(resources.dirname(this.resource), { relative: true }); this.dirty = this.resource && this.textFileService.isDirty(this.resource); - if (this.dirty && this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (this.dirty && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { this.dirty = false; // no dirty decoration if auto save is on with a short timeout } } diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index a1c0c07debd..b859f25c71f 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -28,15 +28,16 @@ .monaco-workbench .part.statusbar > .left-items, .monaco-workbench .part.statusbar > .right-items { display: flex; - flex-wrap: wrap; /* individual entries should not shrink since we do not control their content */ } .monaco-workbench .part.statusbar > .right-items { - flex-direction: row-reverse; /* ensures that the most right elements wrap last when space is little */ + flex-direction: row-reverse; + flex-wrap: wrap /* ensures that the most right elements wrap last when space is little */; } .monaco-workbench .part.statusbar > .left-items { flex-grow: 1; /* left items push right items to the far right end */ + overflow: hidden; /* Hide the overflowing entries */ } .monaco-workbench .part.statusbar > .items-container > .statusbar-item { diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 2d6dc484f22..c48f38e7118 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -611,7 +611,15 @@ export class CustomTreeView extends Disposable implements ITreeView { if (tree && this.visible) { this.refreshing = true; await Promise.all(elements.map(element => tree.updateChildren(element, true))); - elements.map(element => tree.rerender(element)); + + elements.map(element => { + try { + tree.rerender(element); + } catch { + // noop + } + }); + this.refreshing = false; this.updateContentAreas(); if (this.focused) { diff --git a/src/vs/workbench/browser/parts/views/views.ts b/src/vs/workbench/browser/parts/views/views.ts index 9a0a307dd5c..a0981c5c296 100644 --- a/src/vs/workbench/browser/parts/views/views.ts +++ b/src/vs/workbench/browser/parts/views/views.ts @@ -240,6 +240,9 @@ export class ContributableViewsModel extends Disposable { private _onDidChangeViewState = this._register(new Emitter()); protected readonly onDidChangeViewState: Event = this._onDidChangeViewState.event; + private _onDidChangeActiveViews = this._register(new Emitter()); + readonly onDidChangeActiveViews: Event = this._onDidChangeActiveViews.event; + constructor( container: ViewContainer, viewsService: IViewsService, @@ -469,6 +472,8 @@ export class ContributableViewsModel extends Disposable { if (toAdd.length) { this._onDidAdd.fire(toAdd); } + + this._onDidChangeActiveViews.fire(this.viewDescriptors); } } diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 239514051a2..874677282dd 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -112,7 +112,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView })); result.push(...viewToggleActions); - const parentActions = super.getContextMenuActions(); + const parentActions = this.getViewletContextMenuActions(); if (viewToggleActions.length && parentActions.length) { result.push(new Separator()); } @@ -121,6 +121,10 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView return result; } + protected getViewletContextMenuActions() { + return super.getContextMenuActions(); + } + setVisible(visible: boolean): void { super.setVisible(visible); this.panels.filter(view => view.isVisible() !== visible) @@ -264,7 +268,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView }); } - private toggleViewVisibility(viewId: string): void { + protected toggleViewVisibility(viewId: string): void { const visible = !this.viewsModel.isVisible(viewId); type ViewsToggleVisibilityClassification = { viewId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; @@ -321,6 +325,108 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView } } +export abstract class FilterViewContainerViewlet extends ViewContainerViewlet { + private constantViewDescriptors: Map = new Map(); + private allViews: Map> = new Map(); + private filterValue: string | undefined; + + constructor( + viewletId: string, + onDidChangeFilterValue: Event, + @IConfigurationService configurationService: IConfigurationService, + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, + @ITelemetryService telemetryService: ITelemetryService, + @IStorageService storageService: IStorageService, + @IInstantiationService instantiationService: IInstantiationService, + @IThemeService themeService: IThemeService, + @IContextMenuService contextMenuService: IContextMenuService, + @IExtensionService extensionService: IExtensionService, + @IWorkspaceContextService contextService: IWorkspaceContextService + ) { + super(viewletId, `${viewletId}.state`, false, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); + this._register(onDidChangeFilterValue(newFilterValue => { + this.filterValue = newFilterValue; + this.onFilterChanged(newFilterValue); + })); + + this._register(this.viewsModel.onDidChangeActiveViews((viewDescriptors) => { + viewDescriptors.forEach(descriptor => { + let filterOnValue = this.getFilterOn(descriptor); + if (!filterOnValue) { + return; + } + if (!this.allViews.has(filterOnValue)) { + this.allViews.set(filterOnValue, new Map()); + } + this.allViews.get(filterOnValue)!.set(descriptor.id, descriptor); + if (filterOnValue !== this.filterValue) { + this.viewsModel.setVisible(descriptor.id, false); + } + }); + })); + } + + protected addConstantViewDescriptors(constantViewDescriptors: IViewDescriptor[]) { + constantViewDescriptors.forEach(viewDescriptor => this.constantViewDescriptors.set(viewDescriptor.id, viewDescriptor)); + } + + protected abstract getFilterOn(viewDescriptor: IViewDescriptor): string | undefined; + + private onFilterChanged(newFilterValue: string) { + this.getViewsNotForTarget(newFilterValue).forEach(item => this.viewsModel.setVisible(item.id, false)); + this.getViewsForTarget(newFilterValue).forEach(item => this.viewsModel.setVisible(item.id, true)); + } + + getContextMenuActions(): IAction[] { + const result: IAction[] = []; + let viewToggleActions: IAction[] = Array.from(this.constantViewDescriptors.values()).map(viewDescriptor => ({ + id: `${viewDescriptor.id}.toggleVisibility`, + label: viewDescriptor.name, + checked: this.viewsModel.isVisible(viewDescriptor.id), + enabled: viewDescriptor.canToggleVisibility, + run: () => this.toggleViewVisibility(viewDescriptor.id) + })); + + result.push(...viewToggleActions); + const parentActions = this.getViewletContextMenuActions(); + if (viewToggleActions.length && parentActions.length) { + result.push(new Separator()); + } + + result.push(...parentActions); + return result; + } + + private getViewsForTarget(target: string): IViewDescriptor[] { + return this.allViews.has(target) ? Array.from(this.allViews.get(target)!.values()) : []; + } + + private getViewsNotForTarget(target: string): IViewDescriptor[] { + const iterable = this.allViews.keys(); + let key = iterable.next(); + let views: IViewDescriptor[] = []; + while (!key.done) { + if (key.value !== target) { + views = views.concat(this.getViewsForTarget(key.value)); + } + key = iterable.next(); + } + return views; + } + + onDidAddViews(added: IAddedViewDescriptorRef[]): ViewletPanel[] { + const panels: ViewletPanel[] = super.onDidAddViews(added); + for (let i = 0; i < added.length; i++) { + if (this.constantViewDescriptors.has(added[i].viewDescriptor.id)) { + panels[i].setExpanded(false); + } + } + return panels; + } + + abstract getTitle(): string; +} + export class FileIconThemableWorkbenchTree extends WorkbenchTree { constructor( diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 2b634951bf2..854db17c376 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -7,6 +7,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import * as nls from 'vs/nls'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; // Configuration (function registerConfiguration(): void { @@ -14,10 +15,7 @@ import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common // Workbench registry.registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), - 'type': 'object', + ...workbenchConfigurationNodeBase, 'properties': { 'workbench.editor.showTabs': { 'type': 'boolean', diff --git a/src/typings/http-proxy-agent.d.ts b/src/vs/workbench/common/configuration.ts similarity index 51% rename from src/typings/http-proxy-agent.d.ts rename to src/vs/workbench/common/configuration.ts index 3d0071543b4..8405ae63a5f 100644 --- a/src/typings/http-proxy-agent.d.ts +++ b/src/vs/workbench/common/configuration.ts @@ -3,18 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -declare module 'http-proxy-agent' { +import { localize } from 'vs/nls'; +import { IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; - interface IHttpProxyAgentOptions { - host: string; - port: number; - auth?: string; - } - - class HttpProxyAgent { - constructor(proxy: string); - constructor(opts: IHttpProxyAgentOptions); - } - - export = HttpProxyAgent; -} \ No newline at end of file +export const workbenchConfigurationNodeBase = Object.freeze({ + 'id': 'workbench', + 'order': 7, + 'title': localize('workbenchConfigurationTitle', "Workbench"), + 'type': 'object', +}); diff --git a/src/vs/workbench/common/editor/binaryEditorModel.ts b/src/vs/workbench/common/editor/binaryEditorModel.ts index 5f94a8c947a..a911af30a8c 100644 --- a/src/vs/workbench/common/editor/binaryEditorModel.ts +++ b/src/vs/workbench/common/editor/binaryEditorModel.ts @@ -19,7 +19,7 @@ export class BinaryEditorModel extends EditorModel { private readonly mime: string; constructor( - private readonly resource: URI, + public readonly resource: URI, private readonly name: string | undefined, @IFileService private readonly fileService: IFileService ) { @@ -49,13 +49,6 @@ export class BinaryEditorModel extends EditorModel { return this.name || basename(this.resource); } - /** - * The resource of the binary resource. - */ - getResource(): URI { - return this.resource; - } - /** * The size of the binary resource if known. */ diff --git a/src/vs/workbench/common/editor/textEditorModel.ts b/src/vs/workbench/common/editor/textEditorModel.ts index 9385d8e31e6..e95e0d87bae 100644 --- a/src/vs/workbench/common/editor/textEditorModel.ts +++ b/src/vs/workbench/common/editor/textEditorModel.ts @@ -17,7 +17,9 @@ import { withUndefinedAsNull } from 'vs/base/common/types'; * The base text editor model leverages the code editor model. This class is only intended to be subclassed and not instantiated. */ export abstract class BaseTextEditorModel extends EditorModel implements ITextEditorModel, IModeSupport { + protected textEditorModelHandle: URI | null = null; + private createdEditorModel: boolean | undefined; private readonly modelDisposeListener = this._register(new MutableDisposable()); diff --git a/src/vs/workbench/common/editor/untitledTextEditorModel.ts b/src/vs/workbench/common/editor/untitledTextEditorModel.ts index 917f7feeff1..b0d22deb9b3 100644 --- a/src/vs/workbench/common/editor/untitledTextEditorModel.ts +++ b/src/vs/workbench/common/editor/untitledTextEditorModel.ts @@ -16,8 +16,9 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { ITextBufferFactory } from 'vs/editor/common/model'; import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; import { IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService'; +import { IWorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; -export class UntitledTextEditorModel extends BaseTextEditorModel implements IEncodingSupport { +export class UntitledTextEditorModel extends BaseTextEditorModel implements IEncodingSupport, IWorkingCopy { static DEFAULT_CONTENT_CHANGE_BUFFER_DELAY = CONTENT_CHANGE_EVENT_BUFFER_DELAY; @@ -30,33 +31,33 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc private readonly _onDidChangeEncoding: Emitter = this._register(new Emitter()); readonly onDidChangeEncoding: Event = this._onDidChangeEncoding.event; - private dirty: boolean = false; - private versionId: number = 0; - private readonly contentChangeEventScheduler: RunOnceScheduler; + readonly capabilities = 0; + + private dirty = false; + private versionId = 0; + private readonly contentChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidChangeContent.fire(), UntitledTextEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY)); private configuredEncoding?: string; constructor( private readonly preferredMode: string | undefined, - private readonly resource: URI, - private _hasAssociatedFilePath: boolean, + public readonly resource: URI, + public readonly hasAssociatedFilePath: boolean, private readonly initialValue: string | undefined, private preferredEncoding: string | undefined, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IBackupFileService private readonly backupFileService: IBackupFileService, - @ITextResourceConfigurationService private readonly configurationService: ITextResourceConfigurationService + @ITextResourceConfigurationService private readonly configurationService: ITextResourceConfigurationService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService ) { super(modelService, modeService); - this.contentChangeEventScheduler = this._register(new RunOnceScheduler(() => this._onDidChangeContent.fire(), UntitledTextEditorModel.DEFAULT_CONTENT_CHANGE_BUFFER_DELAY)); + // Make known to working copy service + this._register(this.workingCopyService.registerWorkingCopy(this)); this.registerListeners(); } - get hasAssociatedFilePath(): boolean { - return this._hasAssociatedFilePath; - } - private registerListeners(): void { // Config Changes @@ -114,10 +115,6 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc this._onDidChangeDirty.fire(); } - getResource(): URI { - return this.resource; - } - revert(): void { this.setDirty(false); @@ -147,7 +144,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc } // untitled associated to file path are dirty right away as well as untitled with content - this.setDirty(this._hasAssociatedFilePath || !!backup || !!this.initialValue); + this.setDirty(this.hasAssociatedFilePath || !!backup || !!this.initialValue); let untitledContents: ITextBufferFactory; if (backup) { @@ -190,7 +187,7 @@ export class UntitledTextEditorModel extends BaseTextEditorModel implements IEnc // mark the untitled text editor as non-dirty once its content becomes empty and we do // not have an associated path set. we never want dirty indicator in that case. - if (!this._hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') { + if (!this.hasAssociatedFilePath && this.textEditorModel.getLineCount() === 1 && this.textEditorModel.getLineContent(1) === '') { this.setDirty(false); } diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index 188874a1199..81c0439428b 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -593,13 +593,13 @@ export const WINDOW_ACTIVE_BORDER = registerColor('window.activeBorder', { dark: null, light: null, hc: contrastBorder -}, nls.localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client.")); +}, nls.localize('windowActiveBorder', "The color used for the border of the window when it is active. Only supported in the desktop client when using the custom title bar.")); export const WINDOW_INACTIVE_BORDER = registerColor('window.inactiveBorder', { dark: null, light: null, hc: contrastBorder -}, nls.localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client.")); +}, nls.localize('windowInactiveBorder', "The color used for the border of the window when it is inactive. Only supported in the desktop client when using the custom title bar.")); /** * Base class for all themable workbench components. diff --git a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts index 484a7ddce40..21d022ec1b7 100644 --- a/src/vs/workbench/contrib/backup/common/backupModelTracker.ts +++ b/src/vs/workbench/contrib/backup/common/backupModelTracker.ts @@ -6,10 +6,11 @@ import { URI as Uri } from 'vs/base/common/uri'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Disposable } from 'vs/base/common/lifecycle'; -import { ITextFileService, TextFileModelChangeEvent, StateChange, IAutoSaveConfiguration } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, TextFileModelChangeEvent, StateChange } from 'vs/workbench/services/textfile/common/textfiles'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { CONTENT_CHANGE_EVENT_BUFFER_DELAY } from 'vs/platform/files/common/files'; +import { IAutoSaveConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const AUTO_SAVE_AFTER_DELAY_DISABLED_TIME = CONTENT_CHANGE_EVENT_BUFFER_DELAY + 500; @@ -21,6 +22,7 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu @IBackupFileService private readonly backupFileService: IBackupFileService, @ITextFileService private readonly textFileService: ITextFileService, @IUntitledTextEditorService private readonly untitledTextEditorService: IUntitledTextEditorService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); @@ -38,8 +40,8 @@ export class BackupModelTracker extends Disposable implements IWorkbenchContribu this._register(this.untitledTextEditorService.onDidChangeContent(e => this.onUntitledModelChanged(e))); this._register(this.untitledTextEditorService.onDidDisposeModel(e => this.discardBackup(e))); - // Listen to config changes - this._register(this.textFileService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); + // Listen to auto save config changes + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(c => this.onAutoSaveConfigurationChange(c))); } private onAutoSaveConfigurationChange(configuration: IAutoSaveConfiguration): void { diff --git a/src/vs/workbench/contrib/codeActions/common/configuration.ts b/src/vs/workbench/contrib/codeActions/common/configuration.ts index c307bf994b5..d8878cd0181 100644 --- a/src/vs/workbench/contrib/codeActions/common/configuration.ts +++ b/src/vs/workbench/contrib/codeActions/common/configuration.ts @@ -17,6 +17,7 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { CodeActionsExtensionPoint, ContributedCodeAction } from 'vs/workbench/contrib/codeActions/common/extensionPoint'; import { IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig'; const codeActionsOnSaveDefaultProperties = Object.freeze({ 'source.fixAll': { @@ -37,11 +38,7 @@ const codeActionsOnSaveSchema: IConfigurationPropertySchema = { }; export const editorConfiguration = Object.freeze({ - id: 'editor', - order: 5, - type: 'object', - title: nls.localize('editorConfigurationTitle', "Editor"), - overridable: true, + ...editorConfigurationBaseNode, properties: { 'editor.codeActionsOnSave': codeActionsOnSaveSchema, 'editor.codeActionsOnSaveTimeout': { diff --git a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts index bb6029252bf..19f19686a3d 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/suggestEnabledInput/suggestEnabledInput.ts @@ -247,6 +247,10 @@ export class SuggestEnabledInput extends Widget implements IThemable { } } + public onHide(): void { + this.inputWidget.onHide(); + } + public layout(dimension: Dimension): void { this.inputWidget.layout(dimension); this.placeholderText.style.width = `${dimension.width}px`; diff --git a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts index 5ca66eee23d..5a0b6a47e3b 100644 --- a/src/vs/workbench/contrib/customEditor/browser/customEditors.ts +++ b/src/vs/workbench/contrib/customEditor/browser/customEditors.ts @@ -342,7 +342,7 @@ export class CustomEditorContribution implements IWorkbenchContribution { const editors = mergeSort( distinct([ ...this.customEditorService.getUserConfiguredCustomEditors(resource), - ...this.customEditorService.getContributedCustomEditors(resource), + ...this.customEditorService.getContributedCustomEditors(resource).filter(x => x.priority !== CustomEditorPriority.option), ], editor => editor.id), (a, b) => { return priorityToRank(a.priority) - priorityToRank(b.priority); diff --git a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts index b8eaf3ae0d0..d544ec1ee51 100644 --- a/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts +++ b/src/vs/workbench/contrib/customEditor/browser/webviewEditor.contribution.ts @@ -18,6 +18,7 @@ import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEdito import './commands'; import { CustomFileEditorInput } from './customEditorInput'; import { CustomEditorContribution, customEditorsAssociationsKey, CustomEditorService } from './customEditors'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; registerSingleton(ICustomEditorService, CustomEditorService); @@ -39,10 +40,7 @@ Registry.as(EditorInputExtensions.EditorInputFactor Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), - 'type': 'object', + ...workbenchConfigurationNodeBase, 'properties': { [customEditorsAssociationsKey]: { type: 'array', diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 1706204f2eb..df3cc534863 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -800,7 +800,7 @@ class DisconnectAction extends Action { private readonly session: IDebugSession, @ICommandService private readonly commandService: ICommandService ) { - super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action disconnect'); + super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action codicon-debug-disconnect'); } public run(): Promise { diff --git a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts index c4f71f9db26..0c4a83d2cb4 100644 --- a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts @@ -416,7 +416,7 @@ export class ConfigurationManager implements IConfigurationManager { return candidates.then(debuggers => { debuggers.sort((first, second) => first.label.localeCompare(second.label)); const picks = debuggers.map(c => ({ label: c.label, debugger: c })); - return this.quickInputService.pick<{ label: string, debugger: Debugger | undefined }>([...picks, { type: 'separator' }, { label: 'More...', debugger: undefined }], { placeHolder: nls.localize('selectDebug', "Select Environment") }) + return this.quickInputService.pick<{ label: string, debugger: Debugger | undefined }>([...picks, { type: 'separator' }, { label: nls.localize('more', "More..."), debugger: undefined }], { placeHolder: nls.localize('selectDebug', "Select Environment") }) .then(picked => { if (picked && picked.debugger) { return picked.debugger; diff --git a/src/vs/workbench/contrib/debug/browser/debugService.ts b/src/vs/workbench/contrib/debug/browser/debugService.ts index 1eb19f2c61d..031da0c11ab 100644 --- a/src/vs/workbench/contrib/debug/browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/browser/debugService.ts @@ -488,8 +488,6 @@ export class DebugService implements IDebugService { } const errorMessage = error instanceof Error ? error.message : error; - this.telemetryDebugMisconfiguration(session.configuration ? session.configuration.type : undefined, errorMessage); - await this.showError(errorMessage, isErrorWithActions(error) ? error.actions : []); return false; } @@ -1201,19 +1199,6 @@ export class DebugService implements IDebugService { }); } - private telemetryDebugMisconfiguration(debugType: string | undefined, message: string): Promise { - /* __GDPR__ - "debugMisconfiguration" : { - "type" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "error": { "classification": "CallstackOrException", "purpose": "FeatureInsight" } - } - */ - return this.telemetryService.publicLog('debugMisconfiguration', { - type: debugType, - error: message - }); - } - private telemetryDebugAddBreakpoint(breakpoint: IBreakpoint, context: string): Promise { /* __GDPR__ "debugAddBreakpoint" : { diff --git a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts index 6283cda2f78..d9b5232c0eb 100644 --- a/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts +++ b/src/vs/workbench/contrib/debug/browser/extensionHostDebugService.ts @@ -18,6 +18,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IWorkspaceProvider, IWorkspace } from 'vs/workbench/services/host/browser/browserHostService'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; +import { ILogService } from 'vs/platform/log/common/log'; class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient implements IExtensionHostDebugService { @@ -25,7 +26,8 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i constructor( @IRemoteAgentService remoteAgentService: IRemoteAgentService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @ILogService logService: ILogService ) { const connection = remoteAgentService.getConnection(); let channel: IChannel; @@ -34,7 +36,7 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i } else { channel = { call: async () => undefined, listen: () => Event.None } as any; // TODO@weinand TODO@isidorn fallback? - console.warn('Extension Host Debugging not available due to missing connection.'); + logService.warn('Extension Host Debugging not available due to missing connection.'); } super(channel); @@ -43,7 +45,7 @@ class BrowserExtensionHostDebugService extends ExtensionHostDebugChannelClient i this.workspaceProvider = environmentService.options.workspaceProvider; } else { this.workspaceProvider = { open: async () => undefined, workspace: undefined }; - console.warn('Extension Host Debugging not available due to missing workspace provider.'); + logService.warn('Extension Host Debugging not available due to missing workspace provider.'); } // Reload window on reload request diff --git a/src/vs/workbench/contrib/debug/browser/linkDetector.ts b/src/vs/workbench/contrib/debug/browser/linkDetector.ts index baca730b769..0d115223420 100644 --- a/src/vs/workbench/contrib/debug/browser/linkDetector.ts +++ b/src/vs/workbench/contrib/debug/browser/linkDetector.ts @@ -142,7 +142,7 @@ export class LinkDetector { private decorateLink(link: HTMLElement, onclick: () => void) { link.classList.add('link'); link.title = platform.isMacintosh ? nls.localize('fileLinkMac', "Cmd + click to follow link") : nls.localize('fileLink', "Ctrl + click to follow link"); - link.onmousemove = (event) => link.classList.toggle('pointer', platform.isMacintosh ? event.metaKey : event.ctrlKey); + link.onmousemove = (event) => { link.classList.toggle('pointer', platform.isMacintosh ? event.metaKey : event.ctrlKey); }; link.onmouseleave = () => link.classList.remove('pointer'); link.onclick = (event) => { const selection = window.getSelection(); diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index 3ab961601ac..fd184092abd 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -120,7 +120,8 @@ } .monaco-editor .debug-top-stack-frame.debug-breakpoint-and-top-stack-frame, -.monaco-editor .inline-breakpoint-widget.debug-breakpoint-and-top-stack-frame-at-column { +.monaco-editor .debug-breakpoint.debug-top-stack-frame, +.monaco-editor .debug-breakpoint-and-top-stack-frame-at-column { background: url('current-and-breakpoint.svg') center center no-repeat; } diff --git a/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css b/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css index c16ed97a7b7..a0a76da7ec1 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugToolBar.css @@ -17,9 +17,9 @@ .monaco-workbench .debug-toolbar .monaco-action-bar .action-item.select-container { margin-right: 7px; - } +.monaco-workbench .debug-toolbar .monaco-action-bar .action-item.select-container .monaco-select-box, .monaco-workbench .start-debug-action-item .select-container .monaco-select-box { padding: 0 22px 0 6px; } diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 8ce5999aea8..9847a8b1d06 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -140,9 +140,7 @@ text-transform: uppercase; } -.debug-viewlet .debug-call-stack .thread:hover > .state, -.debug-viewlet .debug-call-stack .session:hover > .state, -.debug-viewlet .debug-call-stack .monaco-list-row.focused .state { +.debug-viewlet .debug-call-stack .monaco-list-row:hover .state { display: none; } @@ -159,6 +157,7 @@ width: 16px; height: 100%; margin-right: 8px; + vertical-align: text-top; } .debug-viewlet .debug-call-stack .thread > .state > .label, @@ -240,7 +239,7 @@ overflow: hidden; } -.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected.focused .codicon { +.debug-viewlet .debug-call-stack .monaco-list:focus .monaco-list-row.selected .codicon { color: inherit !important; } diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 2dc46ce56f9..0e647c09b23 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -1093,6 +1093,9 @@ export class DebugModel implements IDebugModel { } element.enabled = enable; + if (enable) { + this.breakpointsActivated = true; + } this._onDidChangeBreakpoints.fire({ changed: changed }); } @@ -1119,6 +1122,9 @@ export class DebugModel implements IDebugModel { } dbp.enabled = enable; }); + if (enable) { + this.breakpointsActivated = true; + } this._onDidChangeBreakpoints.fire({ changed: changed }); } diff --git a/src/vs/workbench/contrib/experiments/common/experimentService.ts b/src/vs/workbench/contrib/experiments/common/experimentService.ts index 188efd95a27..11b6c10aa51 100644 --- a/src/vs/workbench/contrib/experiments/common/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/common/experimentService.ts @@ -167,18 +167,22 @@ export class ExperimentService extends Disposable implements IExperimentService this.storageService.store(storageKey, JSON.stringify(experimentState), StorageScope.GLOBAL); } - protected getExperiments(): Promise { + protected async getExperiments(): Promise { if (!this.productService.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) { - return Promise.resolve([]); + return []; } - return this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None).then(context => { + + try { + const context = await this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None); if (context.res.statusCode !== 200) { - return Promise.resolve(null); + return null; } - return asJson(context).then((result: any) => { - return result && Array.isArray(result['experiments']) ? result['experiments'] : []; - }); - }, () => Promise.resolve(null)); + const result: any = await asJson(context); + return result && Array.isArray(result['experiments']) ? result['experiments'] : []; + } catch (_e) { + // Bad request or invalid JSON + return null; + } } private loadExperiments(): Promise { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts index 7c0193db0ec..e6681ffe074 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionEditor.ts @@ -452,10 +452,8 @@ export class ExtensionEditor extends BaseEditor { private setSubText(extension: IExtension, reloadAction: ReloadAction, template: IExtensionEditorTemplate): void { hide(template.subtextContainer); - const ignoreAction = this.instantiationService.createInstance(IgnoreExtensionRecommendationAction); - const undoIgnoreAction = this.instantiationService.createInstance(UndoIgnoreExtensionRecommendationAction); - ignoreAction.extension = extension; - undoIgnoreAction.extension = extension; + const ignoreAction = this.instantiationService.createInstance(IgnoreExtensionRecommendationAction, extension); + const undoIgnoreAction = this.instantiationService.createInstance(UndoIgnoreExtensionRecommendationAction, extension); ignoreAction.enabled = false; undoIgnoreAction.enabled = false; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts index e7b3de3e4c1..722c6fb9e9d 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionTipsService.ts @@ -506,15 +506,6 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe private async promptForImportantExeBasedExtension(): Promise { - const storageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; - const config = this.configurationService.getValue(ConfigurationKey); - - if (config.ignoreRecommendations - || config.showRecommendationsOnlyOnDemand - || this.storageService.getBoolean(storageKey, StorageScope.WORKSPACE, false)) { - return false; - } - let recommendationsToSuggest = Object.keys(this._importantExeBasedRecommendations); const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); @@ -527,13 +518,23 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe "exeName": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } } */ - this.telemetryService.publicLog('exeExtensionRecommendations:alreadyInstalled', { extensionId, exeName: tip.exeFriendlyName || basename(tip.windowsPath!) }); + this.telemetryService.publicLog('exeExtensionRecommendations:alreadyInstalled', { extensionId, exeName: basename(tip.windowsPath!) }); }); + if (recommendationsToSuggest.length === 0) { return false; } + const storageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + const config = this.configurationService.getValue(ConfigurationKey); + + if (config.ignoreRecommendations + || config.showRecommendationsOnlyOnDemand + || this.storageService.getBoolean(storageKey, StorageScope.WORKSPACE, false)) { + return false; + } + recommendationsToSuggest = this.filterIgnoredOrNotAllowed(recommendationsToSuggest); if (recommendationsToSuggest.length === 0) { return false; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 1d8099e1d2f..2b847bf7ab5 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -135,9 +135,9 @@ function getRelativeDateLabel(date: Date): string { } export abstract class ExtensionAction extends Action implements IExtensionContainer { - private _extension: IExtension; - get extension(): IExtension { return this._extension; } - set extension(extension: IExtension) { this._extension = extension; this.update(); } + private _extension: IExtension | null = null; + get extension(): IExtension | null { return this._extension; } + set extension(extension: IExtension | null) { this._extension = extension; this.update(); } abstract update(): void; } @@ -150,7 +150,7 @@ export class InstallAction extends ExtensionAction { private static readonly InstallingClass = 'extension-action install installing'; - private _manifest: IExtensionManifest | null; + private _manifest: IExtensionManifest | null = null; set manifest(manifest: IExtensionManifest) { this._manifest = manifest; this.updateLabel(); @@ -193,6 +193,9 @@ export class InstallAction extends ExtensionAction { } private updateLabel(): void { + if (!this.extension) { + return; + } if (this.extension.state === ExtensionState.Installing) { this.label = InstallAction.INSTALLING_LABEL; this.tooltip = InstallAction.INSTALLING_LABEL; @@ -214,6 +217,9 @@ export class InstallAction extends ExtensionAction { } async run(): Promise { + if (!this.extension) { + return; + } this.extensionsWorkbenchService.open(this.extension); alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); @@ -303,7 +309,7 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { // disabled by extension kind or it is a language pack extension && (this.extension.enablementState === EnablementState.DisabledByExtensionKind || isLanguagePackExtension(this.extension.local.manifest)) ) { - const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.server)[0]; + const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server === this.server)[0]; if (extensionInOtherServer) { // Getting installed in other server if (extensionInOtherServer.state === ExtensionState.Installing && !extensionInOtherServer.local) { @@ -320,6 +326,9 @@ export abstract class InstallInOtherServerAction extends ExtensionAction { } async run(): Promise { + if (!this.extension) { + return; + } if (this.server) { this.extensionsWorkbenchService.open(this.extension); alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); @@ -412,11 +421,14 @@ export class UninstallAction extends ExtensionAction { this.enabled = true; } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } alert(localize('uninstallExtensionStart', "Uninstalling extension {0} started.", this.extension.displayName)); return this.extensionsWorkbenchService.uninstall(this.extension).then(() => { - alert(localize('uninstallExtensionComplete', "Please reload Visual Studio Code to complete the uninstallation of the extension {0}.", this.extension.displayName)); + alert(localize('uninstallExtensionComplete', "Please reload Visual Studio Code to complete the uninstallation of the extension {0}.", this.extension!.displayName)); }); } } @@ -527,14 +539,17 @@ export class UpdateAction extends ExtensionAction { this.label = this.extension.outdated ? this.getUpdateLabel(this.extension.latestVersion) : this.getUpdateLabel(); } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } alert(localize('updateExtensionStart', "Updating extension {0} to version {1} started.", this.extension.displayName, this.extension.latestVersion)); return this.install(this.extension); } private install(extension: IExtension): Promise { return this.extensionsWorkbenchService.install(extension).then(() => { - alert(localize('updateExtensionComplete', "Updating extension {0} to version {1} completed.", this.extension.displayName, this.extension.latestVersion)); + alert(localize('updateExtensionComplete', "Updating extension {0} to version {1} completed.", extension.displayName, extension.latestVersion)); }, err => { if (!extension.gallery) { return this.notificationService.error(err); @@ -557,8 +572,6 @@ interface IExtensionActionViewItemOptions extends IActionViewItemOptions { export class ExtensionActionViewItem extends ActionViewItem { - protected options: IExtensionActionViewItemOptions; - constructor(context: any, action: IAction, options: IExtensionActionViewItemOptions = {}) { super(context, action, options); } @@ -566,14 +579,14 @@ export class ExtensionActionViewItem extends ActionViewItem { updateEnabled(): void { super.updateEnabled(); - if (this.label && this.options.tabOnlyOnFocus && this.getAction().enabled && !this._hasFocus) { + if (this.label && (this.options).tabOnlyOnFocus && this.getAction().enabled && !this._hasFocus) { DOM.removeTabIndexAndUpdateFocus(this.label); } } - private _hasFocus: boolean; + private _hasFocus: boolean = false; setFocus(value: boolean): void { - if (!this.options.tabOnlyOnFocus || this._hasFocus === value) { + if (!(this.options).tabOnlyOnFocus || this._hasFocus === value) { return; } this._hasFocus = value; @@ -600,7 +613,7 @@ export abstract class ExtensionDropDownAction extends ExtensionAction { super(id, label, cssClass, enabled); } - private _actionViewItem: DropDownMenuActionViewItem; + private _actionViewItem: DropDownMenuActionViewItem | null = null; createActionViewItem(): DropDownMenuActionViewItem { this._actionViewItem = this.instantiationService.createInstance(DropDownMenuActionViewItem, this, this.tabOnlyOnFocus); return this._actionViewItem; @@ -692,13 +705,14 @@ export class ManageExtensionAction extends ExtensionDropDownAction { groups.push([this.instantiationService.createInstance(UninstallAction)]); groups.push([this.instantiationService.createInstance(InstallAnotherVersionAction)]); - const extensionActions: ExtensionAction[] = [this.instantiationService.createInstance(ExtensionInfoAction)]; - if (this.extension.local && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.configuration) { - extensionActions.push(this.instantiationService.createInstance(ExtensionSettingsAction)); + if (this.extension) { + const extensionActions: ExtensionAction[] = [this.instantiationService.createInstance(ExtensionInfoAction)]; + if (this.extension.local && this.extension.local.manifest.contributes && this.extension.local.manifest.contributes.configuration) { + extensionActions.push(this.instantiationService.createInstance(ExtensionSettingsAction)); + } + groups.push(extensionActions); } - groups.push(extensionActions); - groups.forEach(group => group.forEach(extensionAction => extensionAction.extension = this.extension)); return groups; @@ -742,7 +756,7 @@ export class InstallAnotherVersionAction extends ExtensionAction { } update(): void { - this.enabled = this.extension && !!this.extension.gallery; + this.enabled = !!this.extension && !!this.extension.gallery; } run(): Promise { @@ -752,19 +766,19 @@ export class InstallAnotherVersionAction extends ExtensionAction { return this.quickInputService.pick(this.getVersionEntries(), { placeHolder: localize('selectVersion', "Select Version to Install"), matchOnDetail: true }) .then(pick => { if (pick) { - if (this.extension.version === pick.id) { + if (this.extension!.version === pick.id) { return Promise.resolve(); } - const promise: Promise = pick.latest ? this.extensionsWorkbenchService.install(this.extension) : this.extensionsWorkbenchService.installVersion(this.extension, pick.id); + const promise: Promise = pick.latest ? this.extensionsWorkbenchService.install(this.extension!) : this.extensionsWorkbenchService.installVersion(this.extension!, pick.id); return promise .then(null, err => { - if (!this.extension.gallery) { + if (!this.extension!.gallery) { return this.notificationService.error(err); } console.error(err); - return promptDownloadManually(this.extension.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", this.extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService); + return promptDownloadManually(this.extension!.gallery, localize('failedToInstall', "Failed to install \'{0}\'.", this.extension!.identifier.id), err, this.instantiationService, this.notificationService, this.openerService, this.productService); }); } return null; @@ -772,8 +786,8 @@ export class InstallAnotherVersionAction extends ExtensionAction { } private getVersionEntries(): Promise<(IQuickPickItem & { latest: boolean, id: string })[]> { - return this.extensionGalleryService.getAllVersions(this.extension.gallery!, true) - .then(allVersions => allVersions.map((v, i) => ({ id: v.version, label: v.version, description: `${getRelativeDateLabel(new Date(Date.parse(v.date)))}${v.version === this.extension.version ? ` (${localize('current', "Current")})` : ''}`, latest: i === 0 }))); + return this.extensionGalleryService.getAllVersions(this.extension!.gallery!, true) + .then(allVersions => allVersions.map((v, i) => ({ id: v.version, label: v.version, description: `${getRelativeDateLabel(new Date(Date.parse(v.date)))}${v.version === this.extension!.version ? ` (${localize('current', "Current")})` : ''}`, latest: i === 0 }))); } } @@ -793,7 +807,10 @@ export class ExtensionInfoAction extends ExtensionAction { this.enabled = !!this.extension; } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } const name = localize('extensionInfoName', 'Name: {0}', this.extension.displayName); const id = localize('extensionInfoId', 'Id: {0}', this.extension.identifier.id); @@ -823,7 +840,11 @@ export class ExtensionSettingsAction extends ExtensionAction { update(): void { this.enabled = !!this.extension; } - run(): Promise { + + async run(): Promise { + if (!this.extension) { + return; + } this.preferencesService.openSettings(false, `@ext:${this.extension.identifier.id}`); return Promise.resolve(); } @@ -851,7 +872,10 @@ export class EnableForWorkspaceAction extends ExtensionAction { } } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledWorkspace); } } @@ -878,7 +902,10 @@ export class EnableGloballyAction extends ExtensionAction { } } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.EnabledGlobally); } } @@ -899,14 +926,17 @@ export class DisableForWorkspaceAction extends ExtensionAction { update(): void { this.enabled = false; - if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier) && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { + if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier) && this.workspaceContextService.getWorkbenchState() !== WorkbenchState.EMPTY)) { this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace) && this.extensionEnablementService.canChangeEnablement(this.extension.local); } } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledWorkspace); } } @@ -926,14 +956,17 @@ export class DisableGloballyAction extends ExtensionAction { update(): void { this.enabled = false; - if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))) { + if (this.extension && this.extension.local && this.runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))) { this.enabled = this.extension.state === ExtensionState.Installed && (this.extension.enablementState === EnablementState.EnabledGlobally || this.extension.enablementState === EnablementState.EnabledWorkspace) && this.extensionEnablementService.canChangeEnablement(this.extension.local); } } - run(): Promise { + async run(): Promise { + if (!this.extension) { + return; + } return this.extensionsWorkbenchService.setEnablement(this.extension, EnablementState.DisabledGlobally); } } @@ -1190,11 +1223,11 @@ export class ReloadAction extends ExtensionAction { } private computeReloadState(): void { - if (!this._runningExtensions) { + if (!this._runningExtensions || !this.extension) { return; } const isUninstalled = this.extension.state === ExtensionState.Uninstalled; - const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0]; + const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0]; const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation); if (isUninstalled) { @@ -1242,7 +1275,7 @@ export class ReloadAction extends ExtensionAction { const otherServer = this.extension.server ? this.extension.server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer : null; if (otherServer && this.extension.enablementState === EnablementState.DisabledByExtensionKind) { - const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === otherServer)[0]; + const extensionInOtherServer = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server === otherServer)[0]; // Same extension in other server exists and if (extensionInOtherServer && extensionInOtherServer.local && this.extensionEnablementService.isEnabled(extensionInOtherServer.local)) { this.enabled = true; @@ -1300,7 +1333,7 @@ export class SetColorThemeAction extends ExtensionAction { if (!this.enabled) { return; } - let extensionThemes = SetColorThemeAction.getColorThemes(this.colorThemes, this.extension); + let extensionThemes = SetColorThemeAction.getColorThemes(this.colorThemes, this.extension!); const currentTheme = this.colorThemes.filter(t => t.settingsId === this.configurationService.getValue(COLOR_THEME_SETTING))[0]; showCurrentTheme = showCurrentTheme || extensionThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { @@ -1366,7 +1399,7 @@ export class SetFileIconThemeAction extends ExtensionAction { if (!this.enabled) { return; } - let extensionThemes = SetFileIconThemeAction.getFileIconThemes(this.fileIconThemes, this.extension); + let extensionThemes = SetFileIconThemeAction.getFileIconThemes(this.fileIconThemes, this.extension!); const currentTheme = this.fileIconThemes.filter(t => t.settingsId === this.configurationService.getValue(ICON_THEME_SETTING))[0] || this.workbenchThemeService.getFileIconTheme(); showCurrentTheme = showCurrentTheme || extensionThemes.some(t => t.id === currentTheme.id); if (showCurrentTheme) { @@ -1719,9 +1752,8 @@ export class IgnoreExtensionRecommendationAction extends Action { private static readonly Class = 'extension-action ignore'; - extension: IExtension; - constructor( + private readonly extension: IExtension, @IExtensionTipsService private readonly extensionsTipsService: IExtensionTipsService, ) { super(IgnoreExtensionRecommendationAction.ID, 'Ignore Recommendation'); @@ -1743,9 +1775,8 @@ export class UndoIgnoreExtensionRecommendationAction extends Action { private static readonly Class = 'extension-action undo-ignore'; - extension: IExtension; - constructor( + private readonly extension: IExtension, @IExtensionTipsService private readonly extensionsTipsService: IExtensionTipsService, ) { super(UndoIgnoreExtensionRecommendationAction.ID, 'Undo'); @@ -2389,9 +2420,9 @@ export class StatusLabelAction extends Action implements IExtensionContainer { private status: ExtensionState | null = null; private enablementState: EnablementState | null = null; - private _extension: IExtension; - get extension(): IExtension { return this._extension; } - set extension(extension: IExtension) { + private _extension: IExtension | null = null; + get extension(): IExtension | null { return this._extension; } + set extension(extension: IExtension | null) { if (!(this._extension && extension && areSameExtensions(this._extension.identifier, extension.identifier))) { // Different extension. Reset this.initialStatus = null; @@ -2432,21 +2463,21 @@ export class StatusLabelAction extends Action implements IExtensionContainer { const runningExtensions = await this.extensionService.getExtensions(); const canAddExtension = () => { - const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0]; - if (this.extension.local) { - if (runningExtension && this.extension.version === runningExtension.version) { + const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0]; + if (this.extension!.local) { + if (runningExtension && this.extension!.version === runningExtension.version) { return true; } - return this.extensionService.canAddExtension(toExtensionDescription(this.extension.local)); + return this.extensionService.canAddExtension(toExtensionDescription(this.extension!.local)); } return false; }; const canRemoveExtension = () => { - if (this.extension.local) { - if (runningExtensions.every(e => !(areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier) && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(e.extensionLocation)))) { + if (this.extension!.local) { + if (runningExtensions.every(e => !(areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier) && this.extension!.server === this.extensionManagementServerService.getExtensionManagementServer(e.extensionLocation)))) { return true; } - return this.extensionService.canRemoveExtension(toExtensionDescription(this.extension.local)); + return this.extensionService.canRemoveExtension(toExtensionDescription(this.extension!.local)); } return false; }; @@ -2549,7 +2580,7 @@ export class ExtensionToolTipAction extends ExtensionAction { return this.warningAction.tooltip; } if (this.extension && this.extension.local && this.extension.state === ExtensionState.Installed && this._runningExtensions) { - const isRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier)); + const isRunning = this._runningExtensions.some(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier)); const isEnabled = this.extensionEnablementService.isEnabled(this.extension.local); if (isEnabled && isRunning) { @@ -2623,7 +2654,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { return; } if (isLanguagePackExtension(this.extension.local.manifest)) { - if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server !== this.extension.server)) { + if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; this.tooltip = this.extension.server === this.extensionManagementServerService.localExtensionManagementServer ? localize('Install language pack also in remote server', "Install the language pack extension on '{0}' to enable it also there.", this.extensionManagementServerService.remoteExtensionManagementServer.label) @@ -2632,13 +2663,13 @@ export class SystemDisabledWarningAction extends ExtensionAction { return; } if (this.extension.enablementState === EnablementState.DisabledByExtensionKind) { - if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server !== this.extension.server)) { + if (!this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension!.identifier) && e.server !== this.extension!.server)) { this.class = `${SystemDisabledWarningAction.WARNING_CLASS}`; const server = this.extensionManagementServerService.localExtensionManagementServer === this.extension.server ? this.extensionManagementServerService.remoteExtensionManagementServer : this.extensionManagementServerService.localExtensionManagementServer; this.tooltip = localize('Install in other server to enable', "Install the extension on '{0}' to enable.", server.label); return; } - const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension.identifier))[0]; + const runningExtension = this._runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, this.extension!.identifier))[0]; const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null; if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 2bee5aa811e..250084615b9 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -442,7 +442,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio if (this.searchBox) { this.searchBox.layout({ height: 20, width: dimension.width - 34 }); } - super.layout(new Dimension(dimension.width, dimension.height - 38)); + super.layout(new Dimension(dimension.width, dimension.height - 41)); } getOptimalWidth(): number { diff --git a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css index dbf24f49bc5..6f07908168a 100644 --- a/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css +++ b/src/vs/workbench/contrib/extensions/browser/media/extensionsViewlet.css @@ -25,7 +25,7 @@ } .extensions-viewlet > .extensions { - height: calc(100% - 38px); + height: calc(100% - 41px); } .extensions-viewlet > .extensions .extension-view-header .monaco-action-bar { diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts index 6a381ae5127..3324f94e082 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts @@ -501,6 +501,7 @@ suite('ExtensionsTipsService Test', () => { const ignoredExtensionId = 'Some.Extension'; instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: boolean) => a === 'extensionsAssistant/ignored_recommendations' ? '["ms-vscode.vscode"]' : c, + getBoolean: (a: string, b: StorageScope, c: boolean) => c, store: (...args: any[]) => { storageSetterTarget(...args); } @@ -519,7 +520,7 @@ suite('ExtensionsTipsService Test', () => { test('ExtensionTipsService: Get file based recommendations from storage (old format)', () => { const storedRecommendations = '["ms-vscode.csharp", "ms-python.python", "ms-vscode.vscode-typescript-tslint-plugin"]'; - instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => a === 'extensionsAssistant/recommendations' ? storedRecommendations : c }); + instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => a === 'extensionsAssistant/recommendations' ? storedRecommendations : c, getBoolean: (a: string, b: StorageScope, c: boolean) => c }); return setUpFolderWorkspace('myFolder', []).then(() => { testObject = instantiationService.createInstance(ExtensionTipsService); @@ -538,7 +539,7 @@ suite('ExtensionsTipsService Test', () => { const now = Date.now(); const tenDaysOld = 10 * milliSecondsInADay; const storedRecommendations = `{"ms-vscode.csharp": ${now}, "ms-python.python": ${now}, "ms-vscode.vscode-typescript-tslint-plugin": ${now}, "lukehoban.Go": ${tenDaysOld}}`; - instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => a === 'extensionsAssistant/recommendations' ? storedRecommendations : c }); + instantiationService.stub(IStorageService, >{ get: (a: string, b: StorageScope, c?: string) => a === 'extensionsAssistant/recommendations' ? storedRecommendations : c, getBoolean: (a: string, b: StorageScope, c: boolean) => c }); return setUpFolderWorkspace('myFolder', []).then(() => { testObject = instantiationService.createInstance(ExtensionTipsService); diff --git a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts index ddc030e106f..ca9dba559e2 100644 --- a/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts +++ b/src/vs/workbench/contrib/files/browser/editors/fileEditorTracker.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import * as resources from 'vs/base/common/resources'; import { IEditorViewState } from 'vs/editor/common/editorCommon'; import { toResource, SideBySideEditorInput, IWorkbenchEditorConfiguration, SideBySideEditor as SideBySideEditorChoice } from 'vs/workbench/common/editor'; -import { ITextFileService, ITextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ITextFileEditorModel, TextFileModelChangeEvent, ModelState } from 'vs/workbench/services/textfile/common/textfiles'; import { FileOperationEvent, FileOperation, IFileService, FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -61,6 +61,9 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut // Update editors from disk changes this._register(this.fileService.onFileChanges(e => this.onFileChanges(e))); + // Open editors from dirty text file models + this._register(this.textFileService.models.onModelsDirty(e => this.onTextFilesDirty(e))); + // Editor changing this._register(this.editorService.onDidVisibleEditorsChange(() => this.handleOutOfWorkspaceWatchers())); @@ -95,7 +98,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut return resource ? this.textFileService.models.get(resource) : undefined; })) .filter(model => !model.isDirty()), - m => m.getResource().toString() + m => m.resource.toString() ).forEach(model => this.queueModelLoad(model)); } } @@ -296,7 +299,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut // and updated right after. distinct(coalesce([...e.getUpdated(), ...e.getAdded()] .map(u => this.textFileService.models.get(u.resource))) - .filter(model => model && !model.isDirty()), m => m.getResource().toString()) + .filter(model => model && !model.isDirty()), m => m.resource.toString()) .forEach(model => this.queueModelLoad(model)); } @@ -305,7 +308,7 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut // Load model to update (use a queue to prevent accumulation of loads // when the load actually takes long. At most we only want the queue // to have a size of 2 (1 running load and 1 queued load). - const queue = this.modelLoadQueue.queueFor(model.getResource()); + const queue = this.modelLoadQueue.queueFor(model.resource); if (queue.size <= 1) { queue.queue(() => model.load().then(undefined, onUnexpectedError)); } @@ -359,6 +362,31 @@ export class FileEditorTracker extends Disposable implements IWorkbenchContribut }); } + private onTextFilesDirty(e: readonly TextFileModelChangeEvent[]): void { + + // If files become dirty but are not opened, we open it in the background unless there are pending to be saved + this.doOpenDirtyResources(distinct(e.filter(e => { + + // Only dirty models that are not PENDING_SAVE + const model = this.textFileService.models.get(e.resource); + const shouldOpen = model?.isDirty() && !model.hasState(ModelState.PENDING_SAVE); + + // Only if not open already + return shouldOpen && !this.editorService.isOpen({ resource: e.resource }); + }).map(e => e.resource), r => r.toString())); + } + + private doOpenDirtyResources(resources: URI[]): void { + + // Open + this.editorService.openEditors(resources.map(resource => { + return { + resource, + options: { inactive: true, pinned: true, preserveFocus: true } + }; + })); + } + dispose(): void { super.dispose(); diff --git a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts index 92253252003..b683a64070a 100644 --- a/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/textFileEditor.ts @@ -32,6 +32,7 @@ import { IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { MutableDisposable } from 'vs/base/common/lifecycle'; import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/editor'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An implementation of editor for file system resources. @@ -56,9 +57,10 @@ export class TextFileEditor extends BaseTextEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IHostService hostService: IHostService, - @IExplorerService private readonly explorerService: IExplorerService + @IExplorerService private readonly explorerService: IExplorerService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(TextFileEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); this.updateRestoreViewStateConfiguration(); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 3460f9fb6bc..1fb26f4e763 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -18,7 +18,7 @@ import { isMacintosh } from 'vs/base/common/platform'; import { FilesExplorerFocusCondition, ExplorerRootContext, ExplorerFolderContext, ExplorerResourceNotReadonlyContext, ExplorerResourceCut, IExplorerService, ExplorerResourceMoveableToTrash, ExplorerViewletVisibleContext } from 'vs/workbench/contrib/files/common/files'; import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL } from 'vs/workbench/browser/actions/workspaceCommands'; import { CLOSE_SAVED_EDITORS_COMMAND_ID, CLOSE_EDITORS_IN_GROUP_COMMAND_ID, CLOSE_EDITOR_COMMAND_ID, CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; -import { AutoSaveContext } from 'vs/workbench/services/textfile/common/textfiles'; +import { AutoSaveContext } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { WorkbenchListDoubleSelection } from 'vs/platform/list/browser/listService'; import { URI } from 'vs/base/common/uri'; @@ -471,7 +471,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, ({ id: DOWNLOAD_COMMAND_ID, title: DOWNLOAD_LABEL, }, - when: ContextKeyExpr.or(ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), IsWebContext.toNegated()), ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), ExplorerFolderContext.toNegated())) + when: ContextKeyExpr.or(ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), IsWebContext.toNegated()), ContextKeyExpr.and(ResourceContextKey.Scheme.notEqualsTo(Schemas.file), ExplorerFolderContext.toNegated(), ExplorerRootContext.toNegated())) })); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { @@ -495,7 +495,7 @@ MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { id: ADD_ROOT_FOLDER_COMMAND_ID, title: ADD_ROOT_FOLDER_LABEL }, - when: ContextKeyExpr.and(ExplorerRootContext) + when: ExplorerRootContext }); MenuRegistry.appendMenuItem(MenuId.ExplorerContext, { diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index ec20bae93dd..38d7fbac179 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -5,7 +5,6 @@ import 'vs/css!./media/fileactions'; import * as nls from 'vs/nls'; -import * as types from 'vs/base/common/types'; import { isWindows, isWeb } from 'vs/base/common/platform'; import * as extpath from 'vs/base/common/extpath'; import { extname, basename } from 'vs/base/common/path'; @@ -17,7 +16,7 @@ import { Action } from 'vs/base/common/actions'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { VIEWLET_ID, IExplorerService, IFilesConfiguration } from 'vs/workbench/contrib/files/common/files'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IFileService, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { IFileService } from 'vs/platform/files/common/files'; import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { ExplorerViewlet } from 'vs/workbench/contrib/files/browser/explorerViewlet'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; @@ -47,6 +46,7 @@ import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common import { onUnexpectedError, getErrorMessage } from 'vs/base/common/errors'; import { asDomUri, triggerDownload } from 'vs/base/browser/dom'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export const NEW_FILE_COMMAND_ID = 'explorer.newFile'; export const NEW_FILE_LABEL = nls.localize('newFile', "New File"); @@ -496,26 +496,13 @@ export class ToggleAutoSaveAction extends Action { constructor( id: string, label: string, - @IConfigurationService private readonly configurationService: IConfigurationService + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(id, label); } run(): Promise { - const setting = this.configurationService.inspect('files.autoSave'); - let userAutoSaveConfig = setting.user; - if (types.isUndefinedOrNull(userAutoSaveConfig)) { - userAutoSaveConfig = setting.default; // use default if setting not defined - } - - let newAutoSaveValue: string; - if ([AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE].some(s => s === userAutoSaveConfig)) { - newAutoSaveValue = AutoSaveConfiguration.OFF; - } else { - newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY; - } - - return this.configurationService.updateValue('files.autoSave', newAutoSaveValue, ConfigurationTarget.USER); + return this.autoSaveConfigurationService.toggleAutoSave(); } } diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 4e4375262ca..f2332dd7eb5 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -38,6 +38,8 @@ import { ExplorerService } from 'vs/workbench/contrib/files/common/explorerServi import { SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { Schemas } from 'vs/base/common/network'; import { WorkspaceWatcher } from 'vs/workbench/contrib/files/common/workspaceWatcher'; +import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig'; +import { DirtyFilesIndicator } from 'vs/workbench/contrib/files/common/dirtyFilesIndicator'; // Viewlet Action export class OpenExplorerViewletAction extends ShowViewletAction { @@ -170,9 +172,12 @@ Registry.as(WorkbenchExtensions.Workbench).regi // Register uri display for file uris Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FileUriLabelContribution, LifecyclePhase.Starting); -// Workspace Watcher +// Register Workspace Watcher Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspaceWatcher, LifecyclePhase.Restored); +// Register Dirty Files Indicator +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DirtyFilesIndicator, LifecyclePhase.Starting); + // Configuration const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); @@ -339,10 +344,7 @@ configurationRegistry.registerConfiguration({ }); configurationRegistry.registerConfiguration({ - id: 'editor', - order: 5, - title: nls.localize('editorConfigurationTitle', "Editor"), - type: 'object', + ...editorConfigurationBaseNode, properties: { 'editor.formatOnSave': { 'type': 'boolean', @@ -427,7 +429,7 @@ configurationRegistry.registerConfiguration({ 'explorer.compressSingleChildFolders': { 'type': 'boolean', 'description': nls.localize('compressSingleChildFolders', "Controls whether the explorer should compress single child folders in a combined tree element. Useful for Java project folder structures, for example."), - 'default': false + 'default': true }, } }); diff --git a/src/vs/workbench/contrib/files/browser/files.web.contribution.ts b/src/vs/workbench/contrib/files/browser/files.web.contribution.ts index 0a28e1afb60..44d91d66b91 100644 --- a/src/vs/workbench/contrib/files/browser/files.web.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.web.contribution.ts @@ -10,9 +10,6 @@ import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileE import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textFileEditor'; -import { DirtyFilesTracker } from 'vs/workbench/contrib/files/common/dirtyFilesTracker'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; // Register file editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -25,6 +22,3 @@ Registry.as(EditorExtensions.Editors).registerEditor( new SyncDescriptor(FileEditorInput) ] ); - -// Register Dirty Files Tracker -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DirtyFilesTracker, LifecyclePhase.Starting); diff --git a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts index 847d044971b..635033681e1 100644 --- a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts @@ -103,7 +103,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I onSaveError(error: any, model: ITextFileEditorModel): void { const fileOperationError = error as FileOperationError; - const resource = model.getResource(); + const resource = model.resource; let message: string; const primaryActions: IAction[] = []; @@ -113,7 +113,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I if (fileOperationError.fileOperationResult === FileOperationResult.FILE_MODIFIED_SINCE) { // If the user tried to save from the opened conflict editor, show its message again - if (this.activeConflictResolutionResource && this.activeConflictResolutionResource.toString() === model.getResource().toString()) { + if (this.activeConflictResolutionResource && this.activeConflictResolutionResource.toString() === model.resource.toString()) { if (this.storageService.getBoolean(LEARN_MORE_DIRTY_WRITE_IGNORE_KEY, StorageScope.GLOBAL)) { return; // return if this message is ignored } @@ -178,7 +178,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions }; const handle = this.notificationService.notify({ severity: Severity.Error, message, actions }); Event.once(handle.onDidClose)(() => { dispose(primaryActions), dispose(secondaryActions); }); - this.messages.set(model.getResource(), handle); + this.messages.set(model.resource, handle); } dispose(): void { @@ -243,7 +243,7 @@ class ResolveSaveConflictAction extends Action { async run(): Promise { if (!this.model.isDisposed()) { - const resource = this.model.getResource(); + const resource = this.model.resource; const name = basename(resource); const editorLabel = nls.localize('saveConflictDiffLabel', "{0} (in file) ↔ {1} (in {2}) - Resolve save conflict", name, name, this.productService.nameLong); @@ -332,7 +332,7 @@ export const acceptLocalChangesCommand = async (accessor: ServicesAccessor, reso await model.save(); // Reopen file input - await editorService.openEditor({ resource: model.getResource() }, group); + await editorService.openEditor({ resource: model.resource }, group); // Clean up group.closeEditor(editor); @@ -361,7 +361,7 @@ export const revertLocalChangesCommand = async (accessor: ServicesAccessor, reso await model.revert(); // Reopen file input - await editorService.openEditor({ resource: model.getResource() }, group); + await editorService.openEditor({ resource: model.resource }, group); // Clean up group.closeEditor(editor); diff --git a/src/vs/workbench/contrib/files/browser/views/emptyView.ts b/src/vs/workbench/contrib/files/browser/views/emptyView.ts index f24f0128c6f..7d9fbe1c034 100644 --- a/src/vs/workbench/contrib/files/browser/views/emptyView.ts +++ b/src/vs/workbench/contrib/files/browser/views/emptyView.ts @@ -134,6 +134,10 @@ export class EmptyView extends ViewletPanel { // no-op } + focus(): void { + this.focusBody(); + } + focusBody(): void { if (this.button) { this.button.element.focus(); diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index af298d30f03..2a1d6e7a9d6 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -702,7 +702,7 @@ export class FileDragAndDrop implements ITreeDragAndDrop { if (targetStat.children) { const ignoreCase = hasToIgnoreCase(target.resource); targetStat.children.forEach(child => { - targetNames.add(ignoreCase ? child.name : child.name.toLowerCase()); + targetNames.add(ignoreCase ? child.name.toLowerCase() : child.name); }); } @@ -751,9 +751,9 @@ export class FileDragAndDrop implements ITreeDragAndDrop { if (confirmDragAndDrop) { const confirmation = await this.dialogService.confirm({ message: items.length > 1 && items.every(s => s.isRoot) ? localize('confirmRootsMove', "Are you sure you want to change the order of multiple root folders in your workspace?") - : items.length > 1 ? getConfirmMessage(localize('confirmMultiMove', "Are you sure you want to move the following {0} files?", items.length), items.map(s => s.resource)) + : items.length > 1 ? getConfirmMessage(localize('confirmMultiMove', "Are you sure you want to move the following {0} files into '{1}'?", items.length, target.name), items.map(s => s.resource)) : items[0].isRoot ? localize('confirmRootMove', "Are you sure you want to change the order of root folder '{0}' in your workspace?", items[0].name) - : localize('confirmMove', "Are you sure you want to move '{0}'?", items[0].name), + : localize('confirmMove', "Are you sure you want to move '{0}' into '{1}'?", items[0].name, target.name), checkbox: { label: localize('doNotAskAgain', "Do not ask me again") }, diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index abbc65cacae..a182f6f962c 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -15,7 +15,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEditorInput, Verbosity } from 'vs/workbench/common/editor'; import { SaveAllAction, SaveAllInGroupAction, CloseGroupAction } from 'vs/workbench/contrib/files/browser/fileActions'; import { OpenEditorsFocusedContext, ExplorerFocusedContext, IFilesConfiguration, OpenEditor } from 'vs/workbench/contrib/files/common/files'; -import { ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; import { CloseAllEditorsAction, CloseEditorAction } from 'vs/workbench/browser/parts/editor/editorActions'; import { ToggleEditorLayoutAction } from 'vs/workbench/browser/actions/layoutActions'; @@ -43,6 +43,7 @@ import { ElementsDragAndDropData, DesktopDragAndDropData } from 'vs/base/browser import { URI } from 'vs/base/common/uri'; import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { isWeb } from 'vs/base/common/platform'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const $ = dom.$; @@ -76,7 +77,8 @@ export class OpenEditorsView extends ViewletPanel { @IContextKeyService private readonly contextKeyService: IContextKeyService, @IThemeService private readonly themeService: IThemeService, @ITelemetryService private readonly telemetryService: ITelemetryService, - @IMenuService private readonly menuService: IMenuService + @IMenuService private readonly menuService: IMenuService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super({ ...(options as IViewletPanelOptions), @@ -413,7 +415,7 @@ export class OpenEditorsView extends ViewletPanel { } private updateDirtyIndicator(): void { - let dirty = this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY ? this.textFileService.getDirty().length + let dirty = this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY ? this.textFileService.getDirty().length : this.untitledTextEditorService.getDirty().length; if (dirty === 0) { dom.addClass(this.dirtyCountElement, 'hidden'); diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts new file mode 100644 index 00000000000..edb4a75e829 --- /dev/null +++ b/src/vs/workbench/contrib/files/common/dirtyFilesIndicator.ts @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; +import { IWorkingCopyService, IWorkingCopy, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; + +export class DirtyFilesIndicator extends Disposable implements IWorkbenchContribution { + private readonly badgeHandle = this._register(new MutableDisposable()); + + private lastKnownDirtyCount: number | undefined; + + private get hasDirtyCount(): boolean { + return typeof this.lastKnownDirtyCount === 'number' && this.lastKnownDirtyCount > 0; + } + + constructor( + @ILifecycleService private readonly lifecycleService: ILifecycleService, + @IActivityService private readonly activityService: IActivityService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService + ) { + super(); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Working copy dirty indicator + this._register(this.workingCopyService.onDidChangeDirty(c => this.onWorkingCopyDidChangeDirty(c))); + + // Lifecycle + this.lifecycleService.onShutdown(this.dispose, this); + } + + private onWorkingCopyDidChangeDirty(copy: IWorkingCopy): void { + const gotDirty = copy.isDirty(); + if (gotDirty && !!(copy.capabilities & WorkingCopyCapabilities.AutoSave) && this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + return; // do not indicate dirty of working copies that are auto saved after short delay + } + + if (gotDirty || this.hasDirtyCount) { + this.updateActivityBadge(); + } + } + + private updateActivityBadge(): void { + const dirtyCount = this.workingCopyService.dirtyCount; + this.lastKnownDirtyCount = dirtyCount; + + // Indicate dirty count in badge if any + if (dirtyCount > 0) { + this.badgeHandle.value = this.activityService.showActivity( + VIEWLET_ID, + new NumberBadge(dirtyCount, num => num === 1 ? nls.localize('dirtyFile', "1 unsaved file") : nls.localize('dirtyFiles', "{0} unsaved files", dirtyCount)), + 'explorer-viewlet-label' + ); + } else { + this.badgeHandle.clear(); + } + } +} diff --git a/src/vs/workbench/contrib/files/common/dirtyFilesTracker.ts b/src/vs/workbench/contrib/files/common/dirtyFilesTracker.ts deleted file mode 100644 index 6d070bd03e4..00000000000 --- a/src/vs/workbench/contrib/files/common/dirtyFilesTracker.ts +++ /dev/null @@ -1,113 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { VIEWLET_ID } from 'vs/workbench/contrib/files/common/files'; -import { TextFileModelChangeEvent, ITextFileService, AutoSaveMode, ModelState } from 'vs/workbench/services/textfile/common/textfiles'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; -import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; -import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; -import * as arrays from 'vs/base/common/arrays'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; - -export class DirtyFilesTracker extends Disposable implements IWorkbenchContribution { - private lastKnownDirtyCount: number | undefined; - private readonly badgeHandle = this._register(new MutableDisposable()); - - constructor( - @ITextFileService protected readonly textFileService: ITextFileService, - @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IEditorService private readonly editorService: IEditorService, - @IActivityService private readonly activityService: IActivityService, - @IUntitledTextEditorService protected readonly untitledTextEditorService: IUntitledTextEditorService - ) { - super(); - - this.registerListeners(); - } - - private registerListeners(): void { - - // Local text file changes - this._register(this.untitledTextEditorService.onDidChangeDirty(e => this.onUntitledDidChangeDirty(e))); - this._register(this.textFileService.models.onModelsDirty(e => this.onTextFilesDirty(e))); - this._register(this.textFileService.models.onModelsSaved(e => this.onTextFilesSaved(e))); - this._register(this.textFileService.models.onModelsSaveError(e => this.onTextFilesSaveError(e))); - this._register(this.textFileService.models.onModelsReverted(e => this.onTextFilesReverted(e))); - - // Lifecycle - this.lifecycleService.onShutdown(this.dispose, this); - } - - private get hasDirtyCount(): boolean { - return typeof this.lastKnownDirtyCount === 'number' && this.lastKnownDirtyCount > 0; - } - - protected onUntitledDidChangeDirty(resource: URI): void { - const gotDirty = this.untitledTextEditorService.isDirty(resource); - - if (gotDirty || this.hasDirtyCount) { - this.updateActivityBadge(); - } - } - - protected onTextFilesDirty(e: readonly TextFileModelChangeEvent[]): void { - if (this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) { - this.updateActivityBadge(); // no indication needed when auto save is enabled for short delay - } - - // If files become dirty but are not opened, we open it in the background unless there are pending to be saved - this.doOpenDirtyResources(arrays.distinct(e.filter(e => { - - // Only dirty models that are not PENDING_SAVE - const model = this.textFileService.models.get(e.resource); - const shouldOpen = model?.isDirty() && !model.hasState(ModelState.PENDING_SAVE); - - // Only if not open already - return shouldOpen && !this.editorService.isOpen({ resource: e.resource }); - }).map(e => e.resource), r => r.toString())); - } - - private doOpenDirtyResources(resources: URI[]): void { - - // Open - this.editorService.openEditors(resources.map(resource => { - return { - resource, - options: { inactive: true, pinned: true, preserveFocus: true } - }; - })); - } - - protected onTextFilesSaved(e: readonly TextFileModelChangeEvent[]): void { - if (this.hasDirtyCount) { - this.updateActivityBadge(); - } - } - - protected onTextFilesSaveError(e: readonly TextFileModelChangeEvent[]): void { - this.updateActivityBadge(); - } - - protected onTextFilesReverted(e: readonly TextFileModelChangeEvent[]): void { - if (this.hasDirtyCount) { - this.updateActivityBadge(); - } - } - - private updateActivityBadge(): void { - const dirtyCount = this.textFileService.getDirty().length; - this.lastKnownDirtyCount = dirtyCount; - - this.badgeHandle.clear(); - - if (dirtyCount > 0) { - this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, new NumberBadge(dirtyCount, num => num === 1 ? nls.localize('dirtyFile', "1 unsaved file") : nls.localize('dirtyFiles', "{0} unsaved files", dirtyCount)), 'explorer-viewlet-label'); - } - } -} diff --git a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts index 399c49196c9..d4efe1d0084 100644 --- a/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/contrib/files/common/editors/fileEditorInput.ts @@ -11,12 +11,13 @@ import { EncodingMode, ConfirmResult, EditorInput, IFileEditorInput, ITextEditor import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { FileOperationError, FileOperationResult, IFileService } from 'vs/platform/files/common/files'; -import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, TextFileModelChangeEvent, LoadReason, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { FILE_EDITOR_INPUT_ID, TEXT_FILE_EDITOR_ID, BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { ILabelService } from 'vs/platform/label/common/label'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; const enum ForceOpenAs { None, @@ -49,7 +50,8 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { @ITextFileService private readonly textFileService: ITextFileService, @ITextModelService private readonly textModelResolverService: ITextModelService, @ILabelService private readonly labelService: ILabelService, - @IFileService private readonly fileService: IFileService + @IFileService private readonly fileService: IFileService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); @@ -234,7 +236,7 @@ export class FileEditorInput extends EditorInput implements IFileEditorInput { return true; // always indicate dirty state if we are in conflict or error state } - if (this.textFileService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { + if (this.autoSaveConfigurationService.getAutoSaveMode() === AutoSaveMode.AFTER_SHORT_DELAY) { return false; // fast auto save enabled so we do not declare dirty } diff --git a/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts b/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts deleted file mode 100644 index 6f85e8d1bdc..00000000000 --- a/src/vs/workbench/contrib/files/electron-browser/dirtyFilesTracker.ts +++ /dev/null @@ -1,81 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TextFileModelChangeEvent, ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; -import { platform, Platform } from 'vs/base/common/platform'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; -import { IActivityService } from 'vs/workbench/services/activity/common/activity'; -import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { DirtyFilesTracker } from 'vs/workbench/contrib/files/common/dirtyFilesTracker'; -import { IElectronService } from 'vs/platform/electron/node/electron'; - -export class NativeDirtyFilesTracker extends DirtyFilesTracker { - private isDocumentedEdited: boolean; - - constructor( - @ITextFileService protected readonly textFileService: ITextFileService, - @ILifecycleService lifecycleService: ILifecycleService, - @IEditorService editorService: IEditorService, - @IActivityService activityService: IActivityService, - @IUntitledTextEditorService protected readonly untitledTextEditorService: IUntitledTextEditorService, - @IElectronService private readonly electronService: IElectronService - ) { - super(textFileService, lifecycleService, editorService, activityService, untitledTextEditorService); - - this.isDocumentedEdited = false; - } - - protected onUntitledDidChangeDirty(resource: URI): void { - const gotDirty = this.untitledTextEditorService.isDirty(resource); - if ((!this.isDocumentedEdited && gotDirty) || (this.isDocumentedEdited && !gotDirty)) { - this.updateDocumentEdited(); - } - - super.onUntitledDidChangeDirty(resource); - } - - protected onTextFilesDirty(e: readonly TextFileModelChangeEvent[]): void { - if ((this.textFileService.getAutoSaveMode() !== AutoSaveMode.AFTER_SHORT_DELAY) && !this.isDocumentedEdited) { - this.updateDocumentEdited(); // no indication needed when auto save is enabled for short delay - } - - super.onTextFilesDirty(e); - } - - protected onTextFilesSaved(e: readonly TextFileModelChangeEvent[]): void { - if (this.isDocumentedEdited) { - this.updateDocumentEdited(); - } - - super.onTextFilesSaved(e); - } - - protected onTextFilesSaveError(e: readonly TextFileModelChangeEvent[]): void { - if (!this.isDocumentedEdited) { - this.updateDocumentEdited(); - } - - super.onTextFilesSaveError(e); - } - - protected onTextFilesReverted(e: readonly TextFileModelChangeEvent[]): void { - if (this.isDocumentedEdited) { - this.updateDocumentEdited(); - } - - super.onTextFilesReverted(e); - } - - private updateDocumentEdited(): void { - if (platform === Platform.Mac) { - const hasDirtyFiles = this.textFileService.isDirty(); - this.isDocumentedEdited = hasDirtyFiles; - - this.electronService.setDocumentEdited(hasDirtyFiles); - } - } -} diff --git a/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts b/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts index 03a2fa2f421..d5d18ac24ea 100644 --- a/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/electron-browser/files.contribution.ts @@ -10,9 +10,6 @@ import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileE import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { NativeTextFileEditor } from 'vs/workbench/contrib/files/electron-browser/textFileEditor'; -import { NativeDirtyFilesTracker } from 'vs/workbench/contrib/files/electron-browser/dirtyFilesTracker'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; // Register file editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -25,6 +22,3 @@ Registry.as(EditorExtensions.Editors).registerEditor( new SyncDescriptor(FileEditorInput) ] ); - -// Register Dirty Files Tracker -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(NativeDirtyFilesTracker, LifecyclePhase.Starting); diff --git a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts index 18624e12e9a..d2b5d4aa360 100644 --- a/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts +++ b/src/vs/workbench/contrib/files/electron-browser/textFileEditor.ts @@ -25,6 +25,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { IExplorerService } from 'vs/workbench/contrib/files/common/files'; import { IElectronService } from 'vs/platform/electron/node/electron'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * An implementation of editor for file system resources. @@ -46,9 +47,10 @@ export class NativeTextFileEditor extends TextFileEditor { @IElectronService private readonly electronService: IElectronService, @IPreferencesService private readonly preferencesService: IPreferencesService, @IHostService hostService: IHostService, - @IExplorerService explorerService: IExplorerService + @IExplorerService explorerService: IExplorerService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService); + super(telemetryService, fileService, viewletService, instantiationService, contextService, storageService, configurationService, editorService, themeService, editorGroupService, textFileService, hostService, explorerService, autoSaveConfigurationService); } protected handleSetInputError(error: Error, input: FileEditorInput, options: EditorOptions | undefined): void { diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index 9283054b31d..887d6a87d2f 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts @@ -28,6 +28,7 @@ import { INotificationService, Severity } from 'vs/platform/notification/common/ import { IModeService } from 'vs/editor/common/services/modeService'; import { ILabelService } from 'vs/platform/label/common/label'; import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { editorConfigurationBaseNode } from 'vs/editor/common/config/commonEditorConfig'; type FormattingEditProvider = DocumentFormattingEditProvider | DocumentRangeFormattingEditProvider; @@ -152,10 +153,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi ); Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ - id: 'editor', - order: 5, - type: 'object', - overridable: true, + ...editorConfigurationBaseNode, properties: { [DefaultFormatter.configName]: { description: nls.localize('formatter.default', "Defines a default formatter which takes precedence over all other formatter settings. Must be the identifier of an extension contributing a formatter."), diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 48671e13b75..57864213427 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -25,21 +25,10 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ActivePanelContext } from 'vs/workbench/common/panel'; -import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar'; -import { IMarkerService, MarkerStatistics, IMarker, MarkerSeverity, IMarkerData } from 'vs/platform/markers/common/markers'; +import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IEditorContribution } from 'vs/editor/common/editorCommon'; -import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { Event } from 'vs/base/common/event'; -import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { URI } from 'vs/base/common/uri'; -import { isEqual } from 'vs/base/common/resources'; -import { find } from 'vs/base/common/arrays'; -import { Range } from 'vs/editor/common/core/range'; -import { compare } from 'vs/base/common/strings'; registerSingleton(IMarkersWorkbenchService, MarkersWorkbenchService, false); @@ -359,136 +348,3 @@ class MarkersStatusBarContributions extends Disposable implements IWorkbenchCont } workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, LifecyclePhase.Restored); - -class ShowCurrentMarkerInStatusbarContribution extends Disposable implements IEditorContribution { - - public static readonly ID = 'editor.contrib.showCurrentMarkerInStatusbar'; - - private readonly rendererDisposable: MutableDisposable; - - constructor( - private readonly editor: ICodeEditor, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IInstantiationService private readonly instantiationService: IInstantiationService - ) { - super(); - this.rendererDisposable = new MutableDisposable(); - this.onDidConfigurationChange(); - this._register(Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('problems.showCurrentInStatus'))(() => this.onDidConfigurationChange())); - } - - private onDidConfigurationChange(): void { - this.rendererDisposable.clear(); - if (this.configurationService.getValue('problems.showCurrentInStatus')) { - this.rendererDisposable.value = this.instantiationService.createInstance(ShowCurrentMarkerInStatusbarRenderer, this.editor); - } - } -} - -class ShowCurrentMarkerInStatusbarRenderer extends Disposable { - - private readonly statusBarEntryAccessor: MutableDisposable; - private markers: IMarker[] = []; - private currentMarker: IMarker | null = null; - - constructor( - private readonly editor: ICodeEditor, - @IStatusbarService private readonly statusbarService: IStatusbarService, - @IMarkerService private readonly markerService: IMarkerService - ) { - super(); - this.statusBarEntryAccessor = this._register(new MutableDisposable()); - this._register(markerService.onMarkerChanged(changedResources => this.onMarkerChanged(changedResources))); - this._register(editor.onDidChangeModel(() => this.updateMarkers())); - this._register(editor.onDidChangeCursorPosition(() => this.render())); - this.render(); - } - - private render(): void { - const previousMarker = this.currentMarker; - this.currentMarker = this.getMarker(); - if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) { - this.updateStatus(); - } - } - - private hasToUpdateStatus(previousMarker: IMarker | null, currentMarker: IMarker | null): boolean { - if (!currentMarker) { - return true; - } - if (!previousMarker) { - return true; - } - return IMarkerData.makeKey(previousMarker) !== IMarkerData.makeKey(currentMarker); - } - - private updateStatus(): void { - if (this.currentMarker) { - const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0]; - const text = `${this.getType(this.currentMarker)} ${line}`; - if (this.statusBarEntryAccessor.value) { - this.statusBarEntryAccessor.value.update({ text }); - } else { - this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text }, 'statusbar.currentProblem', localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT); - } - } else { - this.statusBarEntryAccessor.clear(); - } - } - - private getType(marker: IMarker): string { - switch (marker.severity) { - case MarkerSeverity.Error: return '$(error)'; - case MarkerSeverity.Warning: return '$(warning)'; - case MarkerSeverity.Info: return '$(info)'; - } - return ''; - } - - private getMarker(): IMarker | null { - const model = this.editor.getModel(); - if (!model) { - return null; - } - const position = this.editor.getPosition(); - if (!position) { - return null; - } - return find(this.markers, marker => Range.containsPosition(marker, position)) || null; - } - - private onMarkerChanged(changedResources: ReadonlyArray): void { - const editorModel = this.editor.getModel(); - if (editorModel && !changedResources.some(r => isEqual(editorModel.uri, r))) { - return; - } - this.updateMarkers(); - } - - private updateMarkers(): void { - const editorModel = this.editor.getModel(); - if (editorModel) { - this.markers = this.markerService.read({ - resource: editorModel.uri, - severities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info - }); - this.markers.sort(compareMarker); - } else { - this.markers = []; - } - this.render(); - } -} - -function compareMarker(a: IMarker, b: IMarker): number { - let res = compare(a.resource.toString(), b.resource.toString()); - if (res === 0) { - res = MarkerSeverity.compare(a.severity, b.severity); - } - if (res === 0) { - res = Range.compareRangesUsingStarts(a, b); - } - return res; -} - -registerEditorContribution(ShowCurrentMarkerInStatusbarContribution.ID, ShowCurrentMarkerInStatusbarContribution); diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index bf6ab98899a..75777a0e8e7 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -466,10 +466,14 @@ export class OutlinePanel extends ViewletPanel { } const textModel = editor.getModel(); - const loadingMessage = oldModel && new TimeoutTimer( - () => this._showMessage(localize('loading', "Loading document symbols for '{0}'...", basename(textModel.uri))), - 100 - ); + + let loadingMessage: IDisposable | undefined; + if (!oldModel) { + loadingMessage = new TimeoutTimer( + () => this._showMessage(localize('loading', "Loading document symbols for '{0}'...", basename(textModel.uri))), + 100 + ); + } const requestDelay = OutlineModel.getRequestDelay(textModel); this._progressBar.infinite().show(requestDelay); diff --git a/src/vs/workbench/contrib/output/browser/logViewer.ts b/src/vs/workbench/contrib/output/browser/logViewer.ts index ce500dfe4a3..31ee5aac462 100644 --- a/src/vs/workbench/contrib/output/browser/logViewer.ts +++ b/src/vs/workbench/contrib/output/browser/logViewer.ts @@ -20,6 +20,7 @@ import { LOG_SCHEME, IFileOutputChannelDescriptor } from 'vs/workbench/contrib/o import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class LogViewerInput extends ResourceEditorInput { @@ -54,9 +55,10 @@ export class LogViewer extends AbstractTextResourceEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(LogViewer.LOG_VIEWER_EDITOR_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); } protected getConfigurationOverrides(): IEditorOptions { diff --git a/src/vs/workbench/contrib/output/browser/outputPanel.ts b/src/vs/workbench/contrib/output/browser/outputPanel.ts index d9eeefed511..c2e14e0763a 100644 --- a/src/vs/workbench/contrib/output/browser/outputPanel.ts +++ b/src/vs/workbench/contrib/output/browser/outputPanel.ts @@ -26,6 +26,7 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class OutputPanel extends AbstractTextResourceEditor { private actions: IAction[] | undefined; @@ -44,9 +45,10 @@ export class OutputPanel extends AbstractTextResourceEditor { @IEditorGroupsService editorGroupService: IEditorGroupsService, @ITextFileService textFileService: ITextFileService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService); + super(OUTPUT_PANEL_ID, telemetryService, instantiationService, storageService, textResourceConfigurationService, themeService, editorGroupService, textFileService, editorService, hostService, autoSaveConfigurationService); this.scopedInstantiationService = instantiationService; } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts b/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts index 4002fe6e377..0bfccbd8aca 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingWidgets.ts @@ -82,7 +82,7 @@ export class KeybindingsSearchWidget extends SearchWidget { stopRecordingKeys(): void { this._reset(); - this.recordDisposables.dispose(); + this.recordDisposables.clear(); } setInputValue(value: string): void { diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 4169b1d34bb..e4b845e14a7 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -65,22 +65,22 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private _onLayout: Emitter = this._register(new Emitter()); readonly onLayout: Event = this._onLayout.event; - private keybindingsEditorModel: KeybindingsEditorModel; + private keybindingsEditorModel: KeybindingsEditorModel | null = null; - private headerContainer: HTMLElement; - private actionsContainer: HTMLElement; - private searchWidget: KeybindingsSearchWidget; + private headerContainer!: HTMLElement; + private actionsContainer!: HTMLElement; + private searchWidget!: KeybindingsSearchWidget; - private overlayContainer: HTMLElement; - private defineKeybindingWidget: DefineKeybindingWidget; + private overlayContainer!: HTMLElement; + private defineKeybindingWidget!: DefineKeybindingWidget; private columnItems: ColumnItem[] = []; - private keybindingsListContainer: HTMLElement; - private unAssignedKeybindingItemToRevealAndFocus: IKeybindingItemEntry | null; - private listEntries: IListEntry[]; - private keybindingsList: WorkbenchList; + private keybindingsListContainer!: HTMLElement; + private unAssignedKeybindingItemToRevealAndFocus: IKeybindingItemEntry | null = null; + private listEntries: IListEntry[] = []; + private keybindingsList!: WorkbenchList; - private dimension: DOM.Dimension; + private dimension: DOM.Dimension | null = null; private delayedFiltering: Delayer; private latestEmptyFilters: string[] = []; private delayedFilterLogging: Delayer; @@ -88,11 +88,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private keybindingFocusContextKey: IContextKey; private searchFocusContextKey: IContextKey; - private actionBar: ActionBar; - private sortByPrecedenceAction: Action; - private recordKeysAction: Action; + private readonly sortByPrecedenceAction: Action; + private readonly recordKeysAction: Action; - private ariaLabelElement: HTMLElement; + private ariaLabelElement!: HTMLElement; constructor( @ITelemetryService telemetryService: ITelemetryService, @@ -115,6 +114,16 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.searchFocusContextKey = CONTEXT_KEYBINDINGS_SEARCH_FOCUS.bindTo(this.contextKeyService); this.keybindingFocusContextKey = CONTEXT_KEYBINDING_FOCUS.bindTo(this.contextKeyService); this.delayedFilterLogging = new Delayer(1000); + + const recordKeysActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS); + const recordKeysActionLabel = localize('recordKeysLabel', "Record Keys"); + this.recordKeysAction = new Action(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, recordKeysActionKeybinding ? localize('recordKeysLabelWithKeybinding', "{0} ({1})", recordKeysActionLabel, recordKeysActionKeybinding.getLabel()) : recordKeysActionLabel, 'codicon-record-keys'); + this.recordKeysAction.checked = false; + + const sortByPrecedenceActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE); + const sortByPrecedenceActionLabel = localize('sortByPrecedeneLabel', "Sort by Precedence"); + this.sortByPrecedenceAction = new Action('keybindings.editor.sortByPrecedence', sortByPrecedenceActionKeybinding ? localize('sortByPrecedeneLabelWithKeybinding', "{0} ({1})", sortByPrecedenceActionLabel, sortByPrecedenceActionKeybinding.getLabel()) : sortByPrecedenceActionLabel, 'codicon-sort-precedence'); + this.sortByPrecedenceAction.checked = false; } createEditor(parent: HTMLElement): void { @@ -298,7 +307,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.overlayContainer.style.position = 'absolute'; this.overlayContainer.style.zIndex = '10'; this.defineKeybindingWidget = this._register(this.instantiationService.createInstance(DefineKeybindingWidget, this.overlayContainer)); - this._register(this.defineKeybindingWidget.onDidChange(keybindingStr => this.defineKeybindingWidget.printExisting(this.keybindingsEditorModel.fetch(`"${keybindingStr}"`).length))); + this._register(this.defineKeybindingWidget.onDidChange(keybindingStr => this.defineKeybindingWidget.printExisting(this.keybindingsEditorModel!.fetch(`"${keybindingStr}"`).length))); this._register(this.defineKeybindingWidget.onShowExistingKeybidings(keybindingStr => this.searchWidget.setValue(`"${keybindingStr}"`))); this.hideOverlayContainer(); } @@ -337,10 +346,6 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.actionsContainer = DOM.append(searchContainer, DOM.$('.keybindings-search-actions-container')); const recordingBadge = this.createRecordingBadge(this.actionsContainer); - const sortByPrecedenceActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE); - const sortByPrecedenceActionLabel = localize('sortByPrecedeneLabel', "Sort by Precedence"); - this.sortByPrecedenceAction = new Action('keybindings.editor.sortByPrecedence', sortByPrecedenceActionKeybinding ? localize('sortByPrecedeneLabelWithKeybinding', "{0} ({1})", sortByPrecedenceActionLabel, sortByPrecedenceActionKeybinding.getLabel()) : sortByPrecedenceActionLabel, 'codicon-sort-precedence'); - this.sortByPrecedenceAction.checked = false; this._register(this.sortByPrecedenceAction.onDidChange(e => { if (e.checked !== undefined) { this.renderKeybindingsEntries(false); @@ -348,10 +353,6 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor this.updateSearchOptions(); })); - const recordKeysActionKeybinding = this.keybindingsService.lookupKeybinding(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS); - const recordKeysActionLabel = localize('recordKeysLabel', "Record Keys"); - this.recordKeysAction = new Action(KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, recordKeysActionKeybinding ? localize('recordKeysLabelWithKeybinding', "{0} ({1})", recordKeysActionLabel, recordKeysActionKeybinding.getLabel()) : recordKeysActionLabel, 'codicon-record-keys'); - this.recordKeysAction.checked = false; this._register(this.recordKeysAction.onDidChange(e => { if (e.checked !== undefined) { DOM.toggleClass(recordingBadge, 'disabled', !e.checked); @@ -370,7 +371,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } })); - this.actionBar = this._register(new ActionBar(this.actionsContainer, { + const actionBar = this._register(new ActionBar(this.actionsContainer, { animated: false, actionViewItemProvider: (action: Action) => { if (action.id === this.sortByPrecedenceAction.id) { @@ -383,7 +384,7 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } })); - this.actionBar.push([this.recordKeysAction, this.sortByPrecedenceAction, clearInputAction], { label: false, icon: true }); + actionBar.push([this.recordKeysAction, this.sortByPrecedenceAction, clearInputAction], { label: false, icon: true }); } private updateSearchOptions(): void { @@ -563,6 +564,9 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor } private layoutKeybindingsList(): void { + if (!this.dimension) { + return; + } let width = this.dimension.width - 27; for (const columnItem of this.columnItems) { if (columnItem.width && !columnItem.proportion) { @@ -855,7 +859,7 @@ abstract class Column extends Disposable { class ActionsColumn extends Column { - private actionBar: ActionBar; + private readonly actionBar: ActionBar; readonly element: HTMLElement; constructor( @@ -864,13 +868,8 @@ class ActionsColumn extends Column { @IKeybindingService private keybindingsService: IKeybindingService ) { super(keybindingsEditor); - this.element = this.create(parent); - } - - create(parent: HTMLElement): HTMLElement { - const actionsContainer = DOM.append(parent, $('.column.actions', { id: 'actions_' + ++Column.COUNTER })); - this.actionBar = new ActionBar(actionsContainer, { animated: false }); - return actionsContainer; + this.element = DOM.append(parent, $('.column.actions', { id: 'actions_' + ++Column.COUNTER })); + this.actionBar = new ActionBar(this.element, { animated: false }); } render(keybindingItemEntry: IKeybindingItemEntry): void { @@ -914,7 +913,7 @@ class ActionsColumn extends Column { class CommandColumn extends Column { - private commandColumn: HTMLElement; + private readonly commandColumn: HTMLElement; readonly element: HTMLElement; constructor( @@ -922,12 +921,7 @@ class CommandColumn extends Column { keybindingsEditor: IKeybindingsEditor, ) { super(keybindingsEditor); - this.element = this.create(parent); - } - - private create(parent: HTMLElement): HTMLElement { - this.commandColumn = DOM.append(parent, $('.column.command', { id: 'command_' + ++Column.COUNTER })); - return this.commandColumn; + this.element = this.commandColumn = DOM.append(parent, $('.column.command', { id: 'command_' + ++Column.COUNTER })); } render(keybindingItemEntry: IKeybindingItemEntry): void { @@ -962,7 +956,7 @@ class CommandColumn extends Column { class KeybindingColumn extends Column { - private keybindingLabel: HTMLElement; + private readonly keybindingLabel: HTMLElement; readonly element: HTMLElement; constructor( @@ -970,13 +964,9 @@ class KeybindingColumn extends Column { keybindingsEditor: IKeybindingsEditor, ) { super(keybindingsEditor); - this.element = this.create(parent); - } - private create(parent: HTMLElement): HTMLElement { - const column = DOM.append(parent, $('.column.keybinding', { id: 'keybinding_' + ++Column.COUNTER })); - this.keybindingLabel = DOM.append(column, $('div.keybinding-label')); - return column; + this.element = DOM.append(parent, $('.column.keybinding', { id: 'keybinding_' + ++Column.COUNTER })); + this.keybindingLabel = DOM.append(this.element, $('div.keybinding-label')); } render(keybindingItemEntry: IKeybindingItemEntry): void { @@ -994,7 +984,7 @@ class KeybindingColumn extends Column { class SourceColumn extends Column { - private sourceColumn: HTMLElement; + private readonly sourceColumn: HTMLElement; readonly element: HTMLElement; constructor( @@ -1002,12 +992,7 @@ class SourceColumn extends Column { keybindingsEditor: IKeybindingsEditor, ) { super(keybindingsEditor); - this.element = this.create(parent); - } - - create(parent: HTMLElement): HTMLElement { - this.sourceColumn = DOM.append(parent, $('.column.source', { id: 'source_' + ++Column.COUNTER })); - return this.sourceColumn; + this.element = this.sourceColumn = DOM.append(parent, $('.column.source', { id: 'source_' + ++Column.COUNTER })); } render(keybindingItemEntry: IKeybindingItemEntry): void { @@ -1024,8 +1009,8 @@ class SourceColumn extends Column { class WhenColumn extends Column { readonly element: HTMLElement; - private whenLabel: HTMLElement; - private whenInput: InputBox; + private readonly whenLabel: HTMLElement; + private readonly whenInput: InputBox; private readonly renderDisposables = this._register(new DisposableStore()); private _onDidAccept: Emitter = this._register(new Emitter()); @@ -1041,14 +1026,11 @@ class WhenColumn extends Column { @IThemeService private readonly themeService: IThemeService ) { super(keybindingsEditor); - this.element = this.create(parent); - } - private create(parent: HTMLElement): HTMLElement { - const column = DOM.append(parent, $('.column.when', { id: 'when_' + ++Column.COUNTER })); + this.element = DOM.append(parent, $('.column.when', { id: 'when_' + ++Column.COUNTER })); - this.whenLabel = DOM.append(column, $('div.when-label')); - this.whenInput = new InputBox(column, this.contextViewService, { + this.whenLabel = DOM.append(this.element, $('div.when-label')); + this.whenInput = new InputBox(this.element, this.contextViewService, { validationOptions: { validation: (value) => { try { @@ -1068,8 +1050,6 @@ class WhenColumn extends Column { this._register(attachInputBoxStyler(this.whenInput, this.themeService)); this._register(DOM.addStandardDisposableListener(this.whenInput.inputElement, DOM.EventType.KEY_DOWN, e => this.onInputKeyDown(e))); this._register(DOM.addDisposableListener(this.whenInput.inputElement, DOM.EventType.BLUR, () => this.cancelEditing())); - - return column; } private onInputKeyDown(e: IKeyboardEvent): void { diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index 5e544b6a1c5..36d2c63d1b0 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -215,7 +215,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: null, primary: KeyMod.CtrlCmd | KeyCode.US_COMMA, handler: (accessor, args: string | undefined) => { - accessor.get(IPreferencesService).openSettings(undefined, typeof args === 'string' ? args : undefined); + const query = typeof args === 'string' ? args : undefined; + accessor.get(IPreferencesService).openSettings(query ? false : undefined, query); } }); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index abec70f1f28..8c5d0468c3e 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -55,6 +55,7 @@ import { DefaultSettingsEditorModel, SettingsEditorModel } from 'vs/workbench/se import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { withNullAsUndefined, withUndefinedAsNull, assertIsDefined } from 'vs/base/common/types'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class PreferencesEditor extends BaseEditor { @@ -981,9 +982,10 @@ export class DefaultPreferencesEditor extends BaseTextEditor { @ITextFileService textFileService: ITextFileService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, - @IHostService hostService: IHostService + @IHostService hostService: IHostService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService); + super(DefaultPreferencesEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, textFileService, editorService, editorGroupService, hostService, autoSaveConfigurationService); } private static _getContributions(): IEditorContributionDescription[] { diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts index f8d98b3d05c..b05433b5f86 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts @@ -4,13 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import * as DOM from 'vs/base/browser/dom'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { ITreeElement } from 'vs/base/browser/ui/tree/tree'; +import { Action } from 'vs/base/common/actions'; import * as arrays from 'vs/base/common/arrays'; import { Delayer, ThrottledDelayer, timeout } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import * as collections from 'vs/base/common/collections'; import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors'; import { Iterator } from 'vs/base/common/iterator'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import * as platform from 'vs/base/common/platform'; import * as strings from 'vs/base/common/strings'; import { isArray, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; @@ -36,13 +41,11 @@ import { AbstractSettingRenderer, ISettingLinkClickEvent, ISettingOverrideClickE import { ISettingsEditorViewState, parseQuery, SearchResultIdx, SearchResultModel, SettingsTreeElement, SettingsTreeGroupChild, SettingsTreeGroupElement, SettingsTreeModel, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; import { settingsTextInputBorder } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { createTOCIterator, TOCTree, TOCTreeModel } from 'vs/workbench/contrib/preferences/browser/tocTree'; -import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS } from 'vs/workbench/contrib/preferences/common/preferences'; +import { CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, EXTENSION_SETTING_TAG, IPreferencesSearchService, ISearchProvider, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IPreferencesService, ISearchResult, ISettingsEditorModel, ISettingsEditorOptions, SettingsEditorOptions, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; import { SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; import { Settings2EditorModel } from 'vs/workbench/services/preferences/common/preferencesModels'; -import { Action } from 'vs/base/common/actions'; -import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; function createGroupIterator(group: SettingsTreeGroupElement): Iterator> { const groupsIt = Iterator.fromArray(group.children); @@ -212,6 +215,7 @@ export class SettingsEditor2 extends BaseEditor { this.createHeader(this.rootElement); this.createBody(this.rootElement); + this.addCtrlAInterceptor(this.rootElement); this.updateStyles(); } @@ -319,6 +323,10 @@ export class SettingsEditor2 extends BaseEditor { this.focusSearch(); } + onHide(): void { + this.searchWidget.onHide(); + } + focusSettings(): void { // Update ARIA global labels const labelElement = this.settingsAriaExtraLabelsContainer.querySelector('#settings_aria_more_actions_shortcut_label'); @@ -583,6 +591,21 @@ export class SettingsEditor2 extends BaseEditor { ); } + private addCtrlAInterceptor(container: HTMLElement): void { + this._register(DOM.addStandardDisposableListener(container, DOM.EventType.KEY_DOWN, (e: StandardKeyboardEvent) => { + if ( + e.keyCode === KeyCode.KEY_A && + (platform.isMacintosh ? e.metaKey : e.ctrlKey) && + e.target.tagName !== 'TEXTAREA' && + e.target.tagName !== 'INPUT' + ) { + // Avoid browser ctrl+a + e.browserEvent.stopPropagation(); + e.browserEvent.preventDefault(); + } + })); + } + private createFocusSink(container: HTMLElement, callback: (e: any) => boolean, label: string): HTMLElement { const listFocusSink = DOM.append(container, $('.settings-tree-focus-sink')); listFocusSink.setAttribute('aria-label', label); diff --git a/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts b/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts new file mode 100644 index 00000000000..3cd6c869fca --- /dev/null +++ b/src/vs/workbench/contrib/remote/browser/explorerViewItems.ts @@ -0,0 +1,114 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import * as dom from 'vs/base/browser/dom'; + +import { IActionRunner, IAction, Action } from 'vs/base/common/actions'; +import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { attachSelectBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; +import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme'; +import { selectBorder } from 'vs/platform/theme/common/colorRegistry'; +import { IRemoteExplorerService, REMOTE_EXPLORER_TYPE_KEY } from 'vs/workbench/services/remote/common/remoteExplorerService'; +import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; +import { IViewDescriptor } from 'vs/workbench/common/views'; +import { startsWith } from 'vs/base/common/strings'; +import { isStringArray } from 'vs/base/common/types'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; + +export interface IRemoteSelectItem extends ISelectOptionItem { + authority: string[]; +} + +export class SwitchRemoteViewItem extends SelectActionViewItem { + + actionRunner!: IActionRunner; + + constructor( + action: IAction, + private readonly optionsItems: IRemoteSelectItem[], + @IThemeService private readonly themeService: IThemeService, + @IContextViewService contextViewService: IContextViewService, + @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IStorageService private readonly storageService: IStorageService + ) { + super(null, action, optionsItems, 0, contextViewService, { ariaLabel: nls.localize('remotes', 'Switch Remote') }); + this._register(attachSelectBoxStyler(this.selectBox, themeService, { + selectBackground: SIDE_BAR_BACKGROUND + })); + + this.setSelectionForConnection(optionsItems, environmentService, remoteExplorerService); + } + + private setSelectionForConnection(optionsItems: IRemoteSelectItem[], environmentService: IWorkbenchEnvironmentService, remoteExplorerService: IRemoteExplorerService) { + if (this.optionsItems.length > 0) { + let index = 0; + const remoteAuthority = environmentService.configuration.remoteAuthority; + const explorerType: string | undefined = remoteAuthority ? remoteAuthority.split('+')[0] : + this.storageService.get(REMOTE_EXPLORER_TYPE_KEY, StorageScope.WORKSPACE) ?? this.storageService.get(REMOTE_EXPLORER_TYPE_KEY, StorageScope.GLOBAL); + if (explorerType) { + index = this.getOptionIndexForExplorerType(optionsItems, explorerType); + } + this.select(index); + remoteExplorerService.targetType = optionsItems[index].authority[0]; + } + } + + private getOptionIndexForExplorerType(optionsItems: IRemoteSelectItem[], explorerType: string): number { + let index = 0; + for (let optionIterator = 0; (optionIterator < this.optionsItems.length) && (index === 0); optionIterator++) { + for (let authorityIterator = 0; authorityIterator < optionsItems[optionIterator].authority.length; authorityIterator++) { + if (optionsItems[optionIterator].authority[authorityIterator] === explorerType) { + index = optionIterator; + break; + } + } + } + return index; + } + + render(container: HTMLElement) { + super.render(container); + dom.addClass(container, 'switch-remote'); + this._register(attachStylerCallback(this.themeService, { selectBorder }, colors => { + container.style.border = colors.selectBorder ? `1px solid ${colors.selectBorder}` : ''; + })); + } + + protected getActionContext(_: string, index: number): any { + return this.optionsItems[index]; + } + + static createOptionItems(views: IViewDescriptor[]): IRemoteSelectItem[] { + let options: IRemoteSelectItem[] = []; + views.forEach(view => { + if (view.group && startsWith(view.group, 'targets') && view.remoteAuthority) { + options.push({ text: view.name, authority: isStringArray(view.remoteAuthority) ? view.remoteAuthority : [view.remoteAuthority] }); + } + }); + return options; + } +} + +export class SwitchRemoteAction extends Action { + + public static readonly ID = 'remote.explorer.switch'; + public static readonly LABEL = nls.localize('remote.explorer.switch', "Switch Remote"); + + constructor( + id: string, label: string, + @IRemoteExplorerService private readonly remoteExplorerService: IRemoteExplorerService + ) { + super(id, label); + } + + public async run(item: IRemoteSelectItem): Promise { + this.remoteExplorerService.targetType = item.authority[0]; + } +} diff --git a/src/vs/workbench/contrib/remote/browser/remote.ts b/src/vs/workbench/contrib/remote/browser/remote.ts index 4d17af30bd3..5a334ade807 100644 --- a/src/vs/workbench/contrib/remote/browser/remote.ts +++ b/src/vs/workbench/contrib/remote/browser/remote.ts @@ -16,10 +16,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; +import { FilterViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { VIEWLET_ID, VIEW_CONTAINER } from 'vs/workbench/contrib/remote/common/remote.contribution'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; -import { IAddedViewDescriptorRef } from 'vs/workbench/browser/parts/views/views'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IViewDescriptor, IViewsRegistry, Extensions } from 'vs/workbench/common/views'; @@ -47,7 +46,10 @@ import Severity from 'vs/base/common/severity'; import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions'; import { IDisposable } from 'vs/base/common/lifecycle'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { SwitchRemoteViewItem, SwitchRemoteAction } from 'vs/workbench/contrib/remote/browser/explorerViewItems'; +import { Action, IActionViewItem, IAction } from 'vs/base/common/actions'; +import { isStringArray } from 'vs/base/common/types'; +import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; interface HelpInformation { extensionDescription: IExtensionDescription; @@ -364,10 +366,9 @@ class HelpPanelDescriptor implements IViewDescriptor { } } - -export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { +export class RemoteViewlet extends FilterViewContainerViewlet implements IViewModel { private helpPanelDescriptor = new HelpPanelDescriptor(this); - + private actions: IAction[] | undefined; helpInformations: HelpInformation[] = []; constructor( @@ -380,10 +381,10 @@ export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { @IThemeService themeService: IThemeService, @IContextMenuService contextMenuService: IContextMenuService, @IExtensionService extensionService: IExtensionService, - @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService, + @IRemoteExplorerService remoteExplorerService: IRemoteExplorerService ) { - super(VIEWLET_ID, `${VIEWLET_ID}.state`, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); - + super(VIEWLET_ID, remoteExplorerService.onDidChangeTargetType, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); + this.addConstantViewDescriptors([this.helpPanelDescriptor]); remoteHelpExtPoint.setHandler((extensions) => { let helpInformation: HelpInformation[] = []; for (let extension of extensions) { @@ -401,6 +402,30 @@ export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { }); } + protected getFilterOn(viewDescriptor: IViewDescriptor): string | undefined { + return isStringArray(viewDescriptor.remoteAuthority) ? viewDescriptor.remoteAuthority[0] : viewDescriptor.remoteAuthority; + } + + public getActionViewItem(action: Action): IActionViewItem | undefined { + if (action.id === SwitchRemoteAction.ID) { + return this.instantiationService.createInstance(SwitchRemoteViewItem, action, SwitchRemoteViewItem.createOptionItems(Registry.as(Extensions.ViewsRegistry).getViews(VIEW_CONTAINER))); + } + + return super.getActionViewItem(action); + } + + public getActions(): IAction[] { + if (!this.actions) { + this.actions = [ + this.instantiationService.createInstance(SwitchRemoteAction, SwitchRemoteAction.ID, SwitchRemoteAction.LABEL), + ]; + this.actions.forEach(a => { + this._register(a); + }); + } + return this.actions; + } + private _handleRemoteInfoExtensionPoint(extension: IExtensionPointUser, helpInformation: HelpInformation[]) { if (!extension.description.enableProposedApi) { return; @@ -419,38 +444,6 @@ export class RemoteViewlet extends ViewContainerViewlet implements IViewModel { }); } - onDidAddViews(added: IAddedViewDescriptorRef[]): ViewletPanel[] { - // too late, already added to the view model - const result = super.onDidAddViews(added); - - const remoteAuthority = this.environmentService.configuration.remoteAuthority; - if (remoteAuthority) { - const actualRemoteAuthority = remoteAuthority.split('+')[0]; - added.forEach((descriptor) => { - const panel = this.getView(descriptor.viewDescriptor.id); - if (!panel) { - return; - } - - const descriptorAuthority = descriptor.viewDescriptor.remoteAuthority; - if (typeof descriptorAuthority === 'undefined') { - panel.setExpanded(true); - } else if (descriptor.viewDescriptor.id === HelpPanel.ID) { - // Do nothing, keep the default behavior for Help - } else { - const descriptorAuthorityArr = Array.isArray(descriptorAuthority) ? descriptorAuthority : [descriptorAuthority]; - if (descriptorAuthorityArr.indexOf(actualRemoteAuthority) >= 0) { - panel.setExpanded(true); - } else { - panel.setExpanded(false); - } - } - }); - } - - return result; - } - getTitle(): string { const title = nls.localize('remote.explorer', "Remote Explorer"); return title; diff --git a/src/vs/workbench/contrib/remote/browser/remoteViewlet.css b/src/vs/workbench/contrib/remote/browser/remoteViewlet.css index 6f6908846c3..d48d027c617 100644 --- a/src/vs/workbench/contrib/remote/browser/remoteViewlet.css +++ b/src/vs/workbench/contrib/remote/browser/remoteViewlet.css @@ -87,3 +87,22 @@ .hc-black .monaco-list .monaco-list-row .remote-help-tree-node-item>.remote-help-tree-node-item-icon.issueReporter { background-image: url('help-report-issue-hc.svg') } + +.monaco-workbench .part > .title > .title-actions .switch-remote { + display: flex; + align-items: center; + font-size: 11px; + margin-right: 0.3em; + height: 20px; + flex-shrink: 1; + margin-top: 7px; +} + +.switch-remote > .monaco-select-box { + border: none; + display: block; +} + +.monaco-workbench .part > .title > .title-actions .switch-remote > .monaco-select-box { + padding-left: 3px; +} diff --git a/src/vs/workbench/contrib/remote/common/remote.contribution.ts b/src/vs/workbench/contrib/remote/common/remote.contribution.ts index 43671fbda5e..5d12781e767 100644 --- a/src/vs/workbench/contrib/remote/common/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/common/remote.contribution.ts @@ -34,7 +34,7 @@ export const VIEW_CONTAINER: ViewContainer = Registry.as('search'); } } diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index 78ec850e816..e6b8aea9346 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -333,7 +333,7 @@ CommandsRegistry.registerCommand({ const RevealInSideBarForSearchResultsCommand: ICommandAction = { id: Constants.RevealInSideBarForSearchResults, - title: nls.localize('revealInSideBar', "Reveal in Explorer") + title: nls.localize('revealInSideBar', "Reveal in Side Bar") }; MenuRegistry.appendMenuItem(MenuId.SearchContext, { diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index f9788455372..150156d7dc2 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -797,8 +797,7 @@ export class SearchView extends ViewletPanel { if (this.searchWidget.searchInput.getRegex()) { selectedText = strings.escapeRegExpCharacters(selectedText); } - - this.searchWidget.searchInput.setValue(selectedText); + this.searchWidget.setValue(selectedText, true); updatedText = true; this.onQueryChanged(); } diff --git a/src/vs/workbench/contrib/search/browser/searchWidget.ts b/src/vs/workbench/contrib/search/browser/searchWidget.ts index 5aa020a689e..d3c846bd0dd 100644 --- a/src/vs/workbench/contrib/search/browser/searchWidget.ts +++ b/src/vs/workbench/contrib/search/browser/searchWidget.ts @@ -15,7 +15,6 @@ import { Action } from 'vs/base/common/actions'; import { Delayer } from 'vs/base/common/async'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import * as strings from 'vs/base/common/strings'; import { CONTEXT_FIND_WIDGET_NOT_VISIBLE } from 'vs/editor/contrib/find/findModel'; import * as nls from 'vs/nls'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; @@ -149,6 +148,8 @@ export class SearchWidget extends Widget { private _onDidHeightChange = this._register(new Emitter()); readonly onDidHeightChange: Event = this._onDidHeightChange.event; + private temporarilySkipSearchOnChange = false; + constructor( container: HTMLElement, options: ISearchWidgetOptions, @@ -404,6 +405,11 @@ export class SearchWidget extends Widget { this._onReplaceToggled.fire(); } + setValue(value: string, skipSearchOnChange: boolean) { + this.searchInput.setValue(value); + this.temporarilySkipSearchOnChange = skipSearchOnChange || this.temporarilySkipSearchOnChange; + } + setReplaceAllActionState(enabled: boolean): void { if (this.replaceAllAction.enabled !== enabled) { this.replaceAllAction.enabled = enabled; @@ -436,12 +442,6 @@ export class SearchWidget extends Widget { return { content: e.message }; } - if (strings.regExpContainsBackreference(value)) { - if (!this.searchConfiguration.usePCRE2) { - return { content: nls.localize('regexp.backreferenceValidationFailure', "Backreferences are not supported") }; - } - } - return null; } @@ -450,8 +450,12 @@ export class SearchWidget extends Widget { this.setReplaceAllActionState(false); if (this.searchConfiguration.searchOnType) { - this._onSearchCancel.fire({ focus: false }); - this._searchDelayer.trigger((() => this.submitSearch()), this.searchConfiguration.searchOnTypeDebouncePeriod); + if (this.temporarilySkipSearchOnChange) { + this.temporarilySkipSearchOnChange = false; + } else { + this._onSearchCancel.fire({ focus: false }); + this._searchDelayer.trigger((() => this.submitSearch()), this.searchConfiguration.searchOnTypeDebouncePeriod); + } } } diff --git a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts index f9cf1306a64..4bd8e74e94e 100644 --- a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts @@ -70,6 +70,10 @@ suite('SearchModel', () => { instantiationService.stub(IModelService, stubModelService(instantiationService)); instantiationService.stub(ISearchService, {}); instantiationService.stub(ISearchService, 'textSearch', Promise.resolve({ results: [] })); + + const config = new TestConfigurationService(); + config.setUserConfiguration('search', { searchOnType: true }); + instantiationService.stub(IConfigurationService, config); }); teardown(() => { @@ -154,9 +158,6 @@ suite('SearchModel', () => { new TextSearchMatch('preview 1', new OneLineRange(1, 4, 11))), aRawMatch('file://c:/2', new TextSearchMatch('preview 2', lineOneRange))]; - const config = new TestConfigurationService(); - config.setUserConfiguration('search', { searchOnType: true }); - instantiationService.stub(IConfigurationService, config); instantiationService.stub(ISearchService, searchServiceWithResults(results)); const testObject: SearchModel = instantiationService.createInstance(SearchModel); diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts index bf413e442d4..10cad170f83 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalColorRegistry.test.ts @@ -19,7 +19,10 @@ function getMockTheme(type: ThemeType): ITheme { label: '', type: type, getColor: (colorId: ColorIdentifier): Color | undefined => themingRegistry.resolveDefaultColor(colorId, theme), - defines: () => true + defines: () => true, + getTokenStyle: () => undefined, + resolveScopes: () => undefined + }; return theme; } @@ -99,4 +102,4 @@ suite('Workbench - TerminalColorRegistry', () => { '#e5e5e5' ], 'The dark terminal colors should be used when a dark theme is active'); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts new file mode 100644 index 00000000000..6a038352e2d --- /dev/null +++ b/src/vs/workbench/contrib/testCustomEditors/browser/testCustomEditors.ts @@ -0,0 +1,242 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { Action } from 'vs/base/common/actions'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; +import { IEditorInputFactory, EditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, EditorModel, ConfirmResult, IRevertOptions, EditorOptions } from 'vs/workbench/common/editor'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorModel } from 'vs/platform/editor/common/editor'; +import { Dimension, addDisposableListener, EventType } from 'vs/base/browser/dom'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { URI } from 'vs/base/common/uri'; +import { isEqual } from 'vs/base/common/resources'; +import { generateUuid } from 'vs/base/common/uuid'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IWorkingCopy, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; + +const CUSTOM_SCHEME = 'testCustomEditor'; +const ENABLE = false; + +class TestCustomEditorsAction extends Action { + + static readonly ID = 'workbench.action.openCustomEditor'; + static readonly LABEL = nls.localize('openCustomEditor', "Test Open Custom Editor"); + + constructor( + id: string, + label: string, + @IEditorService private readonly editorService: IEditorService, + @IInstantiationService private readonly instantiationService: IInstantiationService + ) { + super(id, label); + } + + async run(): Promise { + const input = this.instantiationService.createInstance(TestCustomEditorInput, URI.parse(`${CUSTOM_SCHEME}:/${generateUuid()}`)); + await this.editorService.openEditor(input); + + return true; + } +} + +class TestCustomEditor extends BaseEditor { + + static ID = 'testCustomEditor'; + + private textArea: HTMLTextAreaElement | undefined = undefined; + + constructor( + @ITelemetryService telemetryService: ITelemetryService, + @IThemeService themeService: IThemeService, + @IStorageService storageService: IStorageService + ) { + super(TestCustomEditor.ID, telemetryService, themeService, storageService); + } + + updateStyles(): void { + super.updateStyles(); + + if (this.textArea) { + this.textArea.style.backgroundColor = this.getColor(editorBackground)!.toString(); + this.textArea.style.color = this.getColor(editorForeground)!.toString(); + } + } + + protected createEditor(parent: HTMLElement): void { + this.textArea = document.createElement('textarea'); + this.textArea.style.width = '100%'; + this.textArea.style.height = '100%'; + + parent.appendChild(this.textArea); + + addDisposableListener(this.textArea, EventType.CHANGE, e => this.onDidType()); + addDisposableListener(this.textArea, EventType.KEY_UP, e => this.onDidType()); + + this.updateStyles(); + } + + private onDidType(): void { + if (this._input instanceof TestCustomEditorInput) { + this._input.setValue(this.textArea!.value); + } + } + + async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise { + await super.setInput(input, options, token); + + const model = await input.resolve(); + if (model instanceof TestCustomEditorModel) { + this.textArea!.value = model.value; + } + } + + clearInput() { + super.clearInput(); + + this.textArea!.value = ''; + } + + focus(): void { + this.textArea!.focus(); + } + + layout(dimension: Dimension): void { } +} + +class TestCustomEditorInput extends EditorInput implements IWorkingCopy { + private model: TestCustomEditorModel | undefined = undefined; + + private dirty = false; + + readonly capabilities = 0; + + constructor(public readonly resource: URI, @IWorkingCopyService workingCopyService: IWorkingCopyService) { + super(); + + this._register(workingCopyService.registerWorkingCopy(this)); + } + + getResource(): URI { + return this.resource; + } + + getTypeId(): string { + return TestCustomEditor.ID; + } + + getName(): string { + return this.resource.toString(); + } + + setValue(value: string) { + if (this.model) { + this.model.value = value; + } + + this.setDirty(value.length > 0); + } + + private setDirty(dirty: boolean) { + if (this.dirty !== dirty) { + this.dirty = dirty; + this._onDidChangeDirty.fire(); + } + } + + isDirty(): boolean { + return this.dirty; + } + + confirmSave(): Promise { + // TODO + return Promise.resolve(ConfirmResult.DONT_SAVE); + } + + save(): Promise { + this.setDirty(false); + + return Promise.resolve(true); + } + + revert(options?: IRevertOptions): Promise { + this.setDirty(false); + + return Promise.resolve(true); + } + + async resolve(): Promise { + if (!this.model) { + this.model = new TestCustomEditorModel(this.resource); + } + + return this.model; + } + + matches(other: EditorInput) { + return other instanceof TestCustomEditorInput && isEqual(other.resource, this.resource); + } + + dispose(): void { + this.setDirty(false); + + if (this.model) { + this.model.dispose(); + this.model = undefined; + } + + super.dispose(); + } +} + +class TestCustomEditorModel extends EditorModel { + + public value: string = ''; + + constructor(public readonly resource: URI) { + super(); + } +} + +if (ENABLE) { + Registry.as(EditorExtensions.Editors).registerEditor( + new EditorDescriptor( + TestCustomEditor, + TestCustomEditor.ID, + nls.localize('testCustomEditor', "Test Custom Editor") + ), + [ + new SyncDescriptor(TestCustomEditorInput), + ] + ); + + const registry = Registry.as(Extensions.WorkbenchActions); + + registry.registerWorkbenchAction(new SyncActionDescriptor(TestCustomEditorsAction, TestCustomEditorsAction.ID, TestCustomEditorsAction.LABEL), 'Test Open Custom Editor'); + + class TestCustomEditorInputFactory implements IEditorInputFactory { + + serialize(editorInput: TestCustomEditorInput): string { + return JSON.stringify({ + resource: editorInput.resource.toString() + }); + } + + deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): TestCustomEditorInput { + return instantiationService.createInstance(TestCustomEditorInput, URI.parse(JSON.parse(serializedEditorInput).resource)); + } + } + + Registry.as(EditorInputExtensions.EditorInputFactories).registerEditorInputFactory(TestCustomEditor.ID, TestCustomEditorInputFactory); +} diff --git a/src/vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider.ts b/src/vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider.ts index 763f038e087..2ff0c86458c 100644 --- a/src/vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider.ts +++ b/src/vs/workbench/contrib/url/common/trustedDomainsFileSystemProvider.ts @@ -107,7 +107,7 @@ export class TrustedDomainsFileSystemProvider implements IFileSystemProviderWith writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { try { - const trustedDomainsContent = content.toString(); + const trustedDomainsContent = VSBuffer.wrap(content).toString(); const trustedDomains = parse(trustedDomainsContent); this.storageService.store('http.linkProtectionTrustedDomainsContent', trustedDomainsContent, StorageScope.GLOBAL); diff --git a/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts b/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts index 52c8d7d30c8..f930d68bccf 100644 --- a/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts +++ b/src/vs/workbench/contrib/url/common/trustedDomainsValidator.ts @@ -72,8 +72,8 @@ export class OpenerValidatorContributions implements IWorkbenchContribution { this._productService.nameShort ), [ - localize('openLink', 'Open Link'), - localize('copyLink', 'Copy Link'), + localize('open', 'Open'), + localize('copy', 'Copy'), localize('cancel', 'Cancel'), localize('configureTrustedDomains', 'Configure Trusted Domains') ], @@ -158,7 +158,11 @@ export function isURLDomainTrusted(url: URI, trustedDomains: string[]) { } if (url.authority === parsedTrustedDomain.authority) { - return pathMatches(url.path, parsedTrustedDomain.path); + if (pathMatches(url.path, parsedTrustedDomain.path)) { + return true; + } else { + continue; + } } if (trustedDomains[i].indexOf('*') !== -1) { diff --git a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts index 92cb1c09c88..476d3ab6ce9 100644 --- a/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts +++ b/src/vs/workbench/contrib/userDataSync/browser/userDataSync.ts @@ -25,7 +25,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { isEqual } from 'vs/base/common/resources'; import { IEditorInput } from 'vs/workbench/common/editor'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; -import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { timeout } from 'vs/base/common/async'; const CONTEXT_AUTH_TOKEN_STATE = new RawContextKey('authTokenStatus', AuthTokenStatus.Inactive); @@ -51,7 +50,6 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo @ITextFileService private readonly textFileService: ITextFileService, @IHistoryService private readonly historyService: IHistoryService, @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, - @IQuickInputService private readonly quickInputService: IQuickInputService, ) { super(); this.syncStatusContext = CONTEXT_SYNC_STATE.bindTo(contextKeyService); @@ -138,14 +136,11 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo } private async signIn(): Promise { - const token = await this.quickInputService.input({ placeHolder: localize('enter token', "Please provide the auth bearer token"), ignoreFocusLost: true, }); - if (token) { - await this.authTokenService.updateToken(token); - } + return this.authTokenService.login(); } private async signOut(): Promise { - await this.authTokenService.deleteToken(); + await this.authTokenService.logout(); } private async continueSync(): Promise { @@ -212,6 +207,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo MenuRegistry.appendMenuItem(MenuId.CommandPalette, signInMenuItem); const signOutMenuItem: IMenuItem = { + group: '5_sync', command: { id: 'workbench.userData.actions.logout', title: localize('sign out', "Sign Out") @@ -219,6 +215,7 @@ export class UserDataSyncWorkbenchContribution extends Disposable implements IWo when: ContextKeyExpr.and(CONTEXT_AUTH_TOKEN_STATE.isEqualTo(AuthTokenStatus.Active)), }; CommandsRegistry.registerCommand(signOutMenuItem.command.id, () => this.signOut()); + MenuRegistry.appendMenuItem(MenuId.GlobalActivity, signOutMenuItem); MenuRegistry.appendMenuItem(MenuId.CommandPalette, signOutMenuItem); const startSyncMenuItem: IMenuItem = { diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index e68c960a1f4..9a84c9a84c1 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -29,6 +29,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal'; import { assertIsDefined } from 'vs/base/common/types'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; const $ = dom.$; @@ -188,9 +189,7 @@ Registry.as(WorkbenchExtensions.Workbench) Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': nls.localize('workbenchConfigurationTitle', "Workbench"), + ...workbenchConfigurationNodeBase, 'properties': { 'workbench.tips.enabled': { 'type': 'boolean', diff --git a/src/vs/workbench/contrib/webview/common/resourceLoader.ts b/src/vs/workbench/contrib/webview/common/resourceLoader.ts index 8bde930f42c..ea28683ef4b 100644 --- a/src/vs/workbench/contrib/webview/common/resourceLoader.ts +++ b/src/vs/workbench/contrib/webview/common/resourceLoader.ts @@ -83,7 +83,10 @@ function normalizeRequestPath(requestUri: URI) { // Modern vscode-resources uris put the scheme of the requested resource as the authority if (requestUri.authority) { - return URI.parse(requestUri.authority + ':' + requestUri.path); + return URI.parse(`${requestUri.authority}:${requestUri.path}`).with({ + query: requestUri.query, + fragment: requestUri.fragment + }); } // Old style vscode-resource uris lose the scheme of the resource which means they are unable to diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts index 0b8457849d8..42978506c8c 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.contribution.ts @@ -12,12 +12,11 @@ import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration'; Registry.as(ConfigurationExtensions.Configuration) .registerConfiguration({ - 'id': 'workbench', - 'order': 7, - 'title': localize('workbenchConfigurationTitle', "Workbench"), + ...workbenchConfigurationNodeBase, 'properties': { 'workbench.startupEditor': { 'scope': ConfigurationScope.APPLICATION, // Make sure repositories cannot trigger opening a README for tracking. diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index d5933e71057..d7f2c37ac7f 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -60,6 +60,7 @@ import { ITunnelService, extractLocalHostUriMetaDataForPortMapping } from 'vs/pl import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export class ElectronWindow extends Disposable { @@ -67,14 +68,16 @@ export class ElectronWindow extends Disposable { private readonly touchBarDisposables = this._register(new DisposableStore()); private lastInstalledTouchedBar: ICommandAction[][] | undefined; - private customTitleContextMenuDisposable = this._register(new DisposableStore()); + private readonly customTitleContextMenuDisposable = this._register(new DisposableStore()); private previousConfiguredZoomLevel: number | undefined; - private addFoldersScheduler: RunOnceScheduler; - private pendingFoldersToAdd: URI[]; + private readonly addFoldersScheduler = this._register(new RunOnceScheduler(() => this.doAddFolders(), 100)); + private pendingFoldersToAdd: URI[] = []; - private closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50)); + private readonly closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50)); + + private isDocumentedEdited = false; constructor( @IEditorService private readonly editorService: EditorServiceImpl, @@ -99,13 +102,11 @@ export class ElectronWindow extends Disposable { @IElectronService private readonly electronService: IElectronService, @ITunnelService private readonly tunnelService: ITunnelService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, - @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService + @IElectronEnvironmentService private readonly electronEnvironmentService: IElectronEnvironmentService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService ) { super(); - this.pendingFoldersToAdd = []; - this.addFoldersScheduler = this._register(new RunOnceScheduler(() => this.doAddFolders(), 100)); - this.registerListeners(); this.create(); } @@ -261,6 +262,19 @@ export class ElectronWindow extends Disposable { this.electronService.handleTitleDoubleClick(); })); } + + // Document edited (macOS only): indicate for dirty working copies + if (isMacintosh) { + this._register(this.workingCopyService.onDidChangeDirty(workingCopy => { + const gotDirty = workingCopy.isDirty(); + if ((!this.isDocumentedEdited && gotDirty) || (this.isDocumentedEdited && !gotDirty)) { + const hasDirtyFiles = this.workingCopyService.hasDirty; + this.isDocumentedEdited = hasDirtyFiles; + + this.electronService.setDocumentEdited(hasDirtyFiles); + } + })); + } } private onDidVisibleEditorsChange(): void { @@ -398,29 +412,23 @@ export class ElectronWindow extends Disposable { throw new Error('Prevented call to window.open(). Use IOpenerService instead!'); }; - // Handle internal open() calls - this.openerService.registerOpener({ - open: async (resource: URI, options?: OpenOptions): Promise => { - - // If either the caller wants to open externally or the - // scheme is one where we prefer to open externally - // we handle this resource by delegating the opening to - // the main process to prevent window focus issues. - if (this.shouldOpenExternal(resource, options)) { - const { resolved } = await this.openerService.resolveExternalUri(resource, options); - const success = await this.electronService.openExternal(encodeURI(resolved.toString(true))); - if (!success && resolved.scheme === Schemas.file) { + // Handle external open() calls + this.openerService.setExternalOpener({ + openExternal: async (href: string) => { + const success = await this.electronService.openExternal(href); + if (!success) { + const fileCandidate = URI.parse(href); + if (fileCandidate.scheme === Schemas.file) { // if opening failed, and this is a file, we can still try to reveal it - await this.electronService.showItemInFolder(resolved.fsPath); + await this.electronService.showItemInFolder(fileCandidate.fsPath); } - - return true; } - return false; // not handled by us + return true; } }); + // Register external URI resolver this.openerService.registerExternalUriResolver({ resolveExternalUri: async (uri: URI, options?: OpenOptions) => { if (options?.allowTunneling) { @@ -440,12 +448,6 @@ export class ElectronWindow extends Disposable { }); } - private shouldOpenExternal(resource: URI, options?: OpenOptions) { - const scheme = resource.scheme.toLowerCase(); - const preferOpenExternal = (scheme === Schemas.mailto || scheme === Schemas.http || scheme === Schemas.https); - return options?.openExternal || preferOpenExternal; - } - private updateTouchbarMenu(): void { if (!isMacintosh) { return; // macOS only diff --git a/src/vs/platform/auth/common/authTokenService.ts b/src/vs/workbench/services/authToken/browser/authTokenService.ts similarity index 73% rename from src/vs/platform/auth/common/authTokenService.ts rename to src/vs/workbench/services/authToken/browser/authTokenService.ts index 322ecfb2b09..430a11f7bd8 100644 --- a/src/vs/platform/auth/common/authTokenService.ts +++ b/src/vs/workbench/services/authToken/browser/authTokenService.ts @@ -3,12 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; import { Disposable } from 'vs/base/common/lifecycle'; import { IProductService } from 'vs/platform/product/common/productService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; +import { URI } from 'vs/base/common/uri'; const SERVICE_NAME = 'VS Code'; const ACCOUNT = 'MyAccount'; @@ -21,10 +24,13 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + readonly _onDidGetCallback: Emitter = this._register(new Emitter()); + constructor( @ICredentialsService private readonly credentialsService: ICredentialsService, @IProductService productService: IProductService, @IConfigurationService configurationService: IConfigurationService, + @IQuickInputService private readonly quickInputService: IQuickInputService ) { super(); if (productService.settingsSyncStoreUrl && configurationService.getValue('configurationSync.enableAuth')) { @@ -37,29 +43,35 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { } } - getToken(): Promise { + async getToken(): Promise { if (this.status === AuthTokenStatus.Disabled) { throw new Error('Not enabled'); } - return this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT); + + const token = await this.credentialsService.getPassword(SERVICE_NAME, ACCOUNT); + if (token) { + return token; + } + + return; } - async updateToken(token: string): Promise { - if (this.status === AuthTokenStatus.Disabled) { - throw new Error('Not enabled'); + async login(): Promise { + const token = await this.quickInputService.input({ placeHolder: localize('enter token', "Please provide the auth bearer token"), ignoreFocusLost: true, }); + if (token) { + await this.credentialsService.setPassword(SERVICE_NAME, ACCOUNT, token); + this.setStatus(AuthTokenStatus.Active); } - await this.credentialsService.setPassword(SERVICE_NAME, ACCOUNT, token); - this.setStatus(AuthTokenStatus.Active); } async refreshToken(): Promise { if (this.status === AuthTokenStatus.Disabled) { throw new Error('Not enabled'); } - await this.deleteToken(); + await this.logout(); } - async deleteToken(): Promise { + async logout(): Promise { if (this.status === AuthTokenStatus.Disabled) { throw new Error('Not enabled'); } @@ -75,4 +87,3 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { } } - diff --git a/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts b/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts index b5a2b2d0c0a..7a06e375569 100644 --- a/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts +++ b/src/vs/workbench/services/authToken/electron-browser/authTokenService.ts @@ -9,6 +9,8 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IAuthTokenService, AuthTokenStatus } from 'vs/platform/auth/common/auth'; +import { IURLService } from 'vs/platform/url/common/url'; +import { URI } from 'vs/base/common/uri'; export class AuthTokenService extends Disposable implements IAuthTokenService { @@ -21,8 +23,11 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { private _onDidChangeStatus: Emitter = this._register(new Emitter()); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; + readonly _onDidGetCallback: Emitter = this._register(new Emitter()); + constructor( - @ISharedProcessService sharedProcessService: ISharedProcessService + @ISharedProcessService sharedProcessService: ISharedProcessService, + @IURLService private readonly urlService: IURLService ) { super(); this.channel = sharedProcessService.getChannel('authToken'); @@ -30,22 +35,34 @@ export class AuthTokenService extends Disposable implements IAuthTokenService { this.updateStatus(status); this._register(this.channel.listen('onDidChangeStatus')(status => this.updateStatus(status))); }); + + this.urlService.registerHandler(this); + } + + handleURL(uri: URI) { + if (uri.authority === 'vscode.login') { + this.channel.call('exchangeCodeForToken', uri); + return Promise.resolve(true); + } else { + return Promise.resolve(false); + } } getToken(): Promise { return this.channel.call('getToken'); } - updateToken(token: string): Promise { - return this.channel.call('updateToken', [token]); + login(): Promise { + const callbackUri = this.urlService.create({ authority: 'vscode.login ' }); + return this.channel.call('login', callbackUri); } refreshToken(): Promise { return this.channel.call('getToken'); } - deleteToken(): Promise { - return this.channel.call('deleteToken'); + logout(): Promise { + return this.channel.call('logout'); } private async updateStatus(status: AuthTokenStatus): Promise { diff --git a/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts b/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts new file mode 100644 index 00000000000..9e7ac720a44 --- /dev/null +++ b/src/vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService.ts @@ -0,0 +1,158 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { Event, Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import { IFilesConfiguration, AutoSaveConfiguration } from 'vs/platform/files/common/files'; +import { isUndefinedOrNull } from 'vs/base/common/types'; + +export const AutoSaveContext = new RawContextKey('config.files.autoSave', undefined); + +export interface IAutoSaveConfiguration { + autoSaveDelay?: number; + autoSaveFocusChange: boolean; + autoSaveApplicationChange: boolean; +} + +export const enum AutoSaveMode { + OFF, + AFTER_SHORT_DELAY, + AFTER_LONG_DELAY, + ON_FOCUS_CHANGE, + ON_WINDOW_CHANGE +} + +export const IAutoSaveConfigurationService = createDecorator('autoSaveConfigurationService'); + +export interface IAutoSaveConfigurationService { + + _serviceBrand: undefined; + + readonly onAutoSaveConfigurationChange: Event; + + getAutoSaveMode(): AutoSaveMode; + + getAutoSaveConfiguration(): IAutoSaveConfiguration; + + toggleAutoSave(): Promise; +} + +export class AutoSaveConfigurationService extends Disposable implements IAutoSaveConfigurationService { + + _serviceBrand: undefined; + + private readonly _onAutoSaveConfigurationChange = this._register(new Emitter()); + readonly onAutoSaveConfigurationChange = this._onAutoSaveConfigurationChange.event; + + private configuredAutoSaveDelay?: number; + private configuredAutoSaveOnFocusChange: boolean | undefined; + private configuredAutoSaveOnWindowChange: boolean | undefined; + + private autoSaveContext: IContextKey; + + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { + super(); + + this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); + + const configuration = configurationService.getValue(); + this.onFilesConfigurationChange(configuration); + + this.registerListeners(); + } + + private registerListeners(): void { + + // Files configuration changes + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('files')) { + this.onFilesConfigurationChange(this.configurationService.getValue()); + } + })); + } + + private onFilesConfigurationChange(configuration: IFilesConfiguration): void { + const autoSaveMode = configuration?.files?.autoSave || AutoSaveConfiguration.OFF; + this.autoSaveContext.set(autoSaveMode); + switch (autoSaveMode) { + case AutoSaveConfiguration.AFTER_DELAY: + this.configuredAutoSaveDelay = configuration?.files?.autoSaveDelay; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = false; + break; + + case AutoSaveConfiguration.ON_FOCUS_CHANGE: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = true; + this.configuredAutoSaveOnWindowChange = false; + break; + + case AutoSaveConfiguration.ON_WINDOW_CHANGE: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = true; + break; + + default: + this.configuredAutoSaveDelay = undefined; + this.configuredAutoSaveOnFocusChange = false; + this.configuredAutoSaveOnWindowChange = false; + break; + } + + // Emit as event + this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); + } + + getAutoSaveMode(): AutoSaveMode { + if (this.configuredAutoSaveOnFocusChange) { + return AutoSaveMode.ON_FOCUS_CHANGE; + } + + if (this.configuredAutoSaveOnWindowChange) { + return AutoSaveMode.ON_WINDOW_CHANGE; + } + + if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { + return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; + } + + return AutoSaveMode.OFF; + } + + getAutoSaveConfiguration(): IAutoSaveConfiguration { + return { + autoSaveDelay: this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 ? this.configuredAutoSaveDelay : undefined, + autoSaveFocusChange: !!this.configuredAutoSaveOnFocusChange, + autoSaveApplicationChange: !!this.configuredAutoSaveOnWindowChange + }; + } + + async toggleAutoSave(): Promise { + const setting = this.configurationService.inspect('files.autoSave'); + let userAutoSaveConfig = setting.user; + if (isUndefinedOrNull(userAutoSaveConfig)) { + userAutoSaveConfig = setting.default; // use default if setting not defined + } + + let newAutoSaveValue: string; + if ([AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE].some(s => s === userAutoSaveConfig)) { + newAutoSaveValue = AutoSaveConfiguration.OFF; + } else { + newAutoSaveValue = AutoSaveConfiguration.AFTER_DELAY; + } + + return this.configurationService.updateValue('files.autoSave', newAutoSaveValue, ConfigurationTarget.USER); + } +} + +registerSingleton(IAutoSaveConfigurationService, AutoSaveConfigurationService); diff --git a/src/vs/workbench/services/clipboard/browser/clipboardService.ts b/src/vs/workbench/services/clipboard/browser/clipboardService.ts index 1a9272c7603..85a5d9db60c 100644 --- a/src/vs/workbench/services/clipboard/browser/clipboardService.ts +++ b/src/vs/workbench/services/clipboard/browser/clipboardService.ts @@ -27,6 +27,10 @@ export class BrowserClipboardService implements IClipboardService { newTextarea.style.visibility = 'false'; newTextarea.style.height = '1px'; newTextarea.style.width = '1px'; + newTextarea.setAttribute('aria-hidden', 'true'); + newTextarea.style.position = 'absolute'; + newTextarea.style.top = '-1000'; + newTextarea.style.left = '-1000'; document.body.appendChild(newTextarea); newTextarea.value = text; newTextarea.focus(); diff --git a/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts index ead4e246a36..d0113b72bd7 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditingService.ts @@ -436,7 +436,7 @@ export class ConfigurationEditingService { } if (target === EditableConfigurationTarget.WORKSPACE) { - if (!operation.workspaceStandAloneConfigurationKey) { + if (!operation.workspaceStandAloneConfigurationKey && !OVERRIDE_PROPERTY_PATTERN.test(operation.key)) { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); if (configurationProperties[operation.key].scope === ConfigurationScope.APPLICATION) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_WORKSPACE_CONFIGURATION_APPLICATION, target, operation); @@ -452,7 +452,7 @@ export class ConfigurationEditingService { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_TARGET, target, operation); } - if (!operation.workspaceStandAloneConfigurationKey) { + if (!operation.workspaceStandAloneConfigurationKey && !OVERRIDE_PROPERTY_PATTERN.test(operation.key)) { const configurationProperties = Registry.as(ConfigurationExtensions.Configuration).getConfigurationProperties(); if (configurationProperties[operation.key].scope !== ConfigurationScope.RESOURCE) { return this.reject(ConfigurationEditingErrorCode.ERROR_INVALID_FOLDER_CONFIGURATION, target, operation); diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index 7ad581196cc..d315118d91c 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -18,7 +18,7 @@ import * as uuid from 'vs/base/common/uuid'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; import { ConfigurationEditingService, ConfigurationEditingError, ConfigurationEditingErrorCode, EditableConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditingService'; -import { WORKSPACE_STANDALONE_CONFIGURATIONS } from 'vs/workbench/services/configuration/common/configuration'; +import { WORKSPACE_STANDALONE_CONFIGURATIONS, FOLDER_SETTINGS_PATH } from 'vs/workbench/services/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; @@ -236,6 +236,41 @@ suite('ConfigurationEditingService', () => { }); }); + test('write overridable settings to user settings', () => { + const key = '[language]'; + const value = { 'configurationEditing.service.testSetting': 'overridden value' }; + return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key, value }) + .then(() => { + const contents = fs.readFileSync(globalSettingsFile).toString('utf8'); + const parsed = json.parse(contents); + assert.deepEqual(parsed[key], value); + }); + }); + + test('write overridable settings to workspace settings', () => { + const key = '[language]'; + const value = { 'configurationEditing.service.testSetting': 'overridden value' }; + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key, value }) + .then(() => { + const target = path.join(workspaceDir, FOLDER_SETTINGS_PATH); + const contents = fs.readFileSync(target).toString('utf8'); + const parsed = json.parse(contents); + assert.deepEqual(parsed[key], value); + }); + }); + + test('write overridable settings to workspace folder settings', () => { + const key = '[language]'; + const value = { 'configurationEditing.service.testSetting': 'overridden value' }; + const folderSettingsFile = path.join(workspaceDir, FOLDER_SETTINGS_PATH); + return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE_FOLDER, { key, value }, { scopes: { resource: URI.file(folderSettingsFile) } }) + .then(() => { + const contents = fs.readFileSync(folderSettingsFile).toString('utf8'); + const parsed = json.parse(contents); + assert.deepEqual(parsed[key], value); + }); + }); + test('write workspace standalone setting - empty file', () => { return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'tasks.service.testSetting', value: 'value' }) .then(() => { diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 4035945e8e3..5437e4c00ca 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -301,7 +301,7 @@ export class BrowserWorkbenchEnvironmentService implements IWorkbenchEnvironment break; case 'inspect-brk-extensions': extensionHostDebugEnvironment.params.port = parseInt(value); - extensionHostDebugEnvironment.params.break = false; + extensionHostDebugEnvironment.params.break = true; break; } } diff --git a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts index 93bc95313b8..0e4e725ae64 100644 --- a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts @@ -39,13 +39,15 @@ function storageService(instantiationService: TestInstantiationService): IStorag export class TestExtensionEnablementService extends ExtensionEnablementService { constructor(instantiationService: TestInstantiationService) { + const extensionManagementService = instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService, { onDidInstallExtension: new Emitter().event, onDidUninstallExtension: new Emitter().event } as IExtensionManagementService); + const extensionManagementServerService = instantiationService.get(IExtensionManagementServerService) || instantiationService.stub(IExtensionManagementServerService, { localExtensionManagementServer: { extensionManagementService } }); super( storageService(instantiationService), instantiationService.get(IWorkspaceContextService), instantiationService.get(IWorkbenchEnvironmentService) || instantiationService.stub(IWorkbenchEnvironmentService, { configuration: Object.create(null) } as IWorkbenchEnvironmentService), - instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService, - { onDidInstallExtension: new Emitter().event, onDidUninstallExtension: new Emitter().event } as IExtensionManagementService), - instantiationService.get(IConfigurationService), instantiationService.get(IExtensionManagementServerService), + extensionManagementService, + instantiationService.get(IConfigurationService), + extensionManagementServerService, productService ); } diff --git a/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts b/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts index 2acf10e0b53..744f2860788 100644 --- a/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts +++ b/src/vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService.ts @@ -8,7 +8,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; -class ExtensionResourceLoaderService implements IExtensionResourceLoaderService { +export class ExtensionResourceLoaderService implements IExtensionResourceLoaderService { _serviceBrand: undefined; diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index 64c2e0a526e..1bb31127b8c 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -343,9 +343,13 @@ function patches(originals: typeof http | typeof https, resolveProxy: ReturnType return original.apply(null, arguments as unknown as any[]); } - const optionsPatched = options.agent instanceof ProxyAgent; + const originalAgent = options.agent; + if (originalAgent === true) { + throw new Error('Unexpected agent option: true'); + } + const optionsPatched = originalAgent instanceof ProxyAgent; const config = onRequest && ((options)._vscodeProxySupport || /* LS */ (options)._vscodeSystemProxy) || proxySetting.config; - const useProxySettings = !optionsPatched && (config === 'override' || config === 'on' && !options.agent); + const useProxySettings = !optionsPatched && (config === 'override' || config === 'on' && originalAgent === undefined); const useSystemCertificates = !optionsPatched && certSetting.config && originals === https && !(options as https.RequestOptions).ca; if (useProxySettings || useSystemCertificates) { @@ -367,7 +371,7 @@ function patches(originals: typeof http | typeof https, resolveProxy: ReturnType options.agent = new ProxyAgent({ resolveProxy: resolveProxy.bind(undefined, { useProxySettings, useSystemCertificates }), defaultPort: originals === https ? 443 : 80, - originalAgent: options.agent + originalAgent }); return original(options, callback); } @@ -469,7 +473,9 @@ async function readCaCertificates() { } async function readWindowsCaCertificates() { - const winCA = await import('vscode-windows-ca-certs'); + const winCA = await new Promise((resolve, reject) => { + require(['vscode-windows-ca-certs'], resolve, reject); + }); let ders: any[] = []; const store = winCA(); diff --git a/src/vs/workbench/services/extensions/worker/extHost.services.ts b/src/vs/workbench/services/extensions/worker/extHost.services.ts index 3bdfa1a79fa..ed2e8767cf1 100644 --- a/src/vs/workbench/services/extensions/worker/extHost.services.ts +++ b/src/vs/workbench/services/extensions/worker/extHost.services.ts @@ -13,7 +13,7 @@ import { IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors } from 'vs/work import { IExtHostTerminalService, WorkerExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService'; import { IExtHostTask, WorkerExtHostTask } from 'vs/workbench/api/common/extHostTask'; import { IExtHostDebugService } from 'vs/workbench/api/common/extHostDebugService'; -import { IExtHostSearch } from 'vs/workbench/api/common/extHostSearch'; +import { IExtHostSearch, ExtHostSearch } from 'vs/workbench/api/common/extHostSearch'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService'; import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHostStorage'; @@ -32,6 +32,7 @@ registerSingleton(IExtHostCommands, ExtHostCommands); registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors); registerSingleton(IExtHostStorage, ExtHostStorage); registerSingleton(IExtHostExtensionService, ExtHostExtensionService); +registerSingleton(IExtHostSearch, ExtHostSearch); // register services that only throw errors function NotImplementedProxy(name: ServiceIdentifier): { new(): T } { @@ -51,7 +52,6 @@ function NotImplementedProxy(name: ServiceIdentifier): { new(): T } { registerSingleton(IExtHostTerminalService, WorkerExtHostTerminalService); registerSingleton(IExtHostTask, WorkerExtHostTask); registerSingleton(IExtHostDebugService, class extends NotImplementedProxy(IExtHostDebugService) { }); -registerSingleton(IExtHostSearch, class extends NotImplementedProxy(IExtHostSearch) { }); registerSingleton(IExtensionStoragePaths, class extends NotImplementedProxy(IExtensionStoragePaths) { whenReady = Promise.resolve(); }); diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index 1adf85f8f61..3867576370d 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -11,7 +11,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { Keybinding, ResolvedKeybinding, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; -import { OS, OperatingSystem, isWeb } from 'vs/base/common/platform'; +import { OS, OperatingSystem } from 'vs/base/common/platform'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; @@ -46,7 +46,7 @@ import { isArray } from 'vs/base/common/types'; import { INavigatorWithKeyboard, IKeyboard } from 'vs/workbench/services/keybinding/browser/navigatorKeyboard'; import { ScanCodeUtils, IMMUTABLE_CODE_TO_KEY_CODE } from 'vs/base/common/scanCode'; import { flatten } from 'vs/base/common/arrays'; -import { BrowserFeatures } from 'vs/base/browser/canIUse'; +import { BrowserFeatures, KeyboardSupport } from 'vs/base/browser/canIUse'; interface ContributedKeyBinding { command: string; @@ -241,7 +241,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { this._register(browser.onDidChangeFullscreen(() => { const keyboard: IKeyboard | null = (navigator).keyboard; - if (!BrowserFeatures.fullKeyboard) { + if (BrowserFeatures.keyboard === KeyboardSupport.None) { return; } @@ -352,15 +352,11 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { } private _assertBrowserConflicts(kb: Keybinding, commandId: string): boolean { - if (!isWeb) { + if (BrowserFeatures.keyboard === KeyboardSupport.Always) { return false; } - if (browser.isStandalone) { - return false; - } - - if (browser.isFullscreen() && BrowserFeatures.fullKeyboard) { + if (BrowserFeatures.keyboard === KeyboardSupport.FullScreen && browser.isFullscreen()) { return false; } diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index 8e6059322b1..98c4d011305 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -250,7 +250,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding private parse(model: ITextModel): { result: IUserFriendlyKeybinding[], parseErrors: json.ParseError[] } { const parseErrors: json.ParseError[] = []; - const result = json.parse(model.getValue(), parseErrors, { allowEmptyContent: true }); + const result = json.parse(model.getValue(), parseErrors, { allowTrailingComma: true, allowEmptyContent: true }); return { result, parseErrors }; } diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index d4be17512c0..26baa78b0ab 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -39,7 +39,7 @@ import { KeybindingsEditingService } from 'vs/workbench/services/keybinding/comm import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { IUntitledTextEditorService, UntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService'; -import { TestBackupFileService, TestContextService, TestEditorGroupsService, TestEditorService, TestLifecycleService, TestTextFileService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices'; +import { TestBackupFileService, TestContextService, TestEditorGroupsService, TestEditorService, TestLifecycleService, TestTextFileService, TestTextResourcePropertiesService, TestWorkingCopyService } from 'vs/workbench/test/workbenchTestServices'; import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; @@ -49,6 +49,7 @@ import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-browser/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; class TestEnvironmentService extends NativeWorkbenchEnvironmentService { @@ -67,7 +68,7 @@ interface Modifiers { shiftKey?: boolean; } -suite('KeybindingsEditing', () => { +suite.skip('KeybindingsEditing', () => { let instantiationService: TestInstantiationService; let testObject: KeybindingsEditingService; @@ -93,6 +94,7 @@ suite('KeybindingsEditing', () => { instantiationService.stub(IContextKeyService, instantiationService.createInstance(MockContextKeyService)); instantiationService.stub(IEditorGroupsService, new TestEditorGroupsService()); instantiationService.stub(IEditorService, new TestEditorService()); + instantiationService.stub(IWorkingCopyService, new TestWorkingCopyService()); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IModeService, ModeServiceImpl); instantiationService.stub(ILogService, new NullLogService()); diff --git a/src/vs/workbench/services/remote/common/remoteExplorerService.ts b/src/vs/workbench/services/remote/common/remoteExplorerService.ts new file mode 100644 index 00000000000..7aec6e57689 --- /dev/null +++ b/src/vs/workbench/services/remote/common/remoteExplorerService.ts @@ -0,0 +1,41 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event, Emitter } from 'vs/base/common/event'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; + +export const IRemoteExplorerService = createDecorator('remoteExplorerService'); +export const REMOTE_EXPLORER_TYPE_KEY: string = 'remote.explorerType'; + +export interface IRemoteExplorerService { + _serviceBrand: undefined; + onDidChangeTargetType: Event; + targetType: string; +} + +class RemoteExplorerService implements IRemoteExplorerService { + public _serviceBrand: undefined; + private _targetType: string = ''; + private _onDidChangeTargetType: Emitter = new Emitter(); + public onDidChangeTargetType: Event = this._onDidChangeTargetType.event; + + constructor(@IStorageService private readonly storageService: IStorageService) { } + + set targetType(name: string) { + if (this._targetType !== name) { + this._targetType = name; + this.storageService.store(REMOTE_EXPLORER_TYPE_KEY, this._targetType, StorageScope.WORKSPACE); + this.storageService.store(REMOTE_EXPLORER_TYPE_KEY, this._targetType, StorageScope.GLOBAL); + this._onDidChangeTargetType.fire(this._targetType); + } + } + get targetType(): string { + return this._targetType; + } +} + +registerSingleton(IRemoteExplorerService, RemoteExplorerService, true); diff --git a/src/vs/workbench/services/search/common/textSearchManager.ts b/src/vs/workbench/services/search/common/textSearchManager.ts new file mode 100644 index 00000000000..223374a7bdd --- /dev/null +++ b/src/vs/workbench/services/search/common/textSearchManager.ts @@ -0,0 +1,355 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'vs/base/common/path'; +import { mapArrayOrNot } from 'vs/base/common/arrays'; +import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; +import * as resources from 'vs/base/common/resources'; +import * as glob from 'vs/base/common/glob'; +import { URI } from 'vs/base/common/uri'; +import { IExtendedExtensionSearchOptions, IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchResult, QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/common/search'; +import { TextSearchProvider, TextSearchResult, TextSearchMatch, TextSearchComplete, Range, TextSearchOptions, TextSearchQuery } from 'vs/workbench/services/search/common/searchExtTypes'; +import { nextTick } from 'vs/base/common/process'; + +export interface IFileUtils { + readdir: (resource: URI) => Promise; + toCanonicalName: (encoding: string) => string; +} + +export class TextSearchManager { + + private collector: TextSearchResultsCollector | null = null; + + private isLimitHit = false; + private resultCount = 0; + + constructor(private query: ITextQuery, private provider: TextSearchProvider, private fileUtils: IFileUtils) { } + + search(onProgress: (matches: IFileMatch[]) => void, token: CancellationToken): Promise { + const folderQueries = this.query.folderQueries || []; + const tokenSource = new CancellationTokenSource(); + token.onCancellationRequested(() => tokenSource.cancel()); + + return new Promise((resolve, reject) => { + this.collector = new TextSearchResultsCollector(onProgress); + + let isCanceled = false; + const onResult = (result: TextSearchResult, folderIdx: number) => { + if (isCanceled) { + return; + } + + if (!this.isLimitHit) { + const resultSize = this.resultSize(result); + if (extensionResultIsMatch(result) && typeof this.query.maxResults === 'number' && this.resultCount + resultSize > this.query.maxResults) { + this.isLimitHit = true; + isCanceled = true; + tokenSource.cancel(); + + result = this.trimResultToSize(result, this.query.maxResults - this.resultCount); + } + + const newResultSize = this.resultSize(result); + this.resultCount += newResultSize; + if (newResultSize > 0) { + this.collector!.add(result, folderIdx); + } + } + }; + + // For each root folder + Promise.all(folderQueries.map((fq, i) => { + return this.searchInFolder(fq, r => onResult(r, i), tokenSource.token); + })).then(results => { + tokenSource.dispose(); + this.collector!.flush(); + + const someFolderHitLImit = results.some(result => !!result && !!result.limitHit); + resolve({ + limitHit: this.isLimitHit || someFolderHitLImit, + stats: { + type: 'textSearchProvider' + } + }); + }, (err: Error) => { + tokenSource.dispose(); + const errMsg = toErrorMessage(err); + reject(new Error(errMsg)); + }); + }); + } + + private resultSize(result: TextSearchResult): number { + const match = result; + return Array.isArray(match.ranges) ? + match.ranges.length : + 1; + } + + private trimResultToSize(result: TextSearchMatch, size: number): TextSearchMatch { + const rangesArr = Array.isArray(result.ranges) ? result.ranges : [result.ranges]; + const matchesArr = Array.isArray(result.preview.matches) ? result.preview.matches : [result.preview.matches]; + + return { + ranges: rangesArr.slice(0, size), + preview: { + matches: matchesArr.slice(0, size), + text: result.preview.text + }, + uri: result.uri + }; + } + + private searchInFolder(folderQuery: IFolderQuery, onResult: (result: TextSearchResult) => void, token: CancellationToken): Promise { + const queryTester = new QueryGlobTester(this.query, folderQuery); + const testingPs: Promise[] = []; + const progress = { + report: (result: TextSearchResult) => { + if (!this.validateProviderResult(result)) { + return; + } + + const hasSibling = folderQuery.folder.scheme === 'file' ? + glob.hasSiblingPromiseFn(() => { + return this.fileUtils.readdir(resources.dirname(result.uri)); + }) : + undefined; + + const relativePath = resources.relativePath(folderQuery.folder, result.uri); + if (relativePath) { + testingPs.push( + queryTester.includedInQuery(relativePath, path.basename(relativePath), hasSibling) + .then(included => { + if (included) { + onResult(result); + } + })); + } + } + }; + + const searchOptions = this.getSearchOptionsForFolder(folderQuery); + return new Promise(resolve => nextTick(resolve)) + .then(() => this.provider.provideTextSearchResults(patternInfoToQuery(this.query.contentPattern), searchOptions, progress, token)) + .then(result => { + return Promise.all(testingPs) + .then(() => result); + }); + } + + private validateProviderResult(result: TextSearchResult): boolean { + if (extensionResultIsMatch(result)) { + if (Array.isArray(result.ranges)) { + if (!Array.isArray(result.preview.matches)) { + console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same type.'); + return false; + } + + if ((result.preview.matches).length !== result.ranges.length) { + console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same length.'); + return false; + } + } else { + if (Array.isArray(result.preview.matches)) { + console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same length.'); + return false; + } + } + } + + return true; + } + + private getSearchOptionsForFolder(fq: IFolderQuery): TextSearchOptions { + const includes = resolvePatternsForProvider(this.query.includePattern, fq.includePattern); + const excludes = resolvePatternsForProvider(this.query.excludePattern, fq.excludePattern); + + const options = { + folder: URI.from(fq.folder), + excludes, + includes, + useIgnoreFiles: !fq.disregardIgnoreFiles, + useGlobalIgnoreFiles: !fq.disregardGlobalIgnoreFiles, + followSymlinks: !fq.ignoreSymlinks, + encoding: fq.fileEncoding && this.fileUtils.toCanonicalName(fq.fileEncoding), + maxFileSize: this.query.maxFileSize, + maxResults: this.query.maxResults, + previewOptions: this.query.previewOptions, + afterContext: this.query.afterContext, + beforeContext: this.query.beforeContext + }; + (options).usePCRE2 = this.query.usePCRE2; + return options; + } +} + +function patternInfoToQuery(patternInfo: IPatternInfo): TextSearchQuery { + return { + isCaseSensitive: patternInfo.isCaseSensitive || false, + isRegExp: patternInfo.isRegExp || false, + isWordMatch: patternInfo.isWordMatch || false, + isMultiline: patternInfo.isMultiline || false, + pattern: patternInfo.pattern + }; +} + +export class TextSearchResultsCollector { + private _batchedCollector: BatchedCollector; + + private _currentFolderIdx: number = -1; + private _currentUri: URI | undefined; + private _currentFileMatch: IFileMatch | null = null; + + constructor(private _onResult: (result: IFileMatch[]) => void) { + this._batchedCollector = new BatchedCollector(512, items => this.sendItems(items)); + } + + add(data: TextSearchResult, folderIdx: number): void { + // Collects TextSearchResults into IInternalFileMatches and collates using BatchedCollector. + // This is efficient for ripgrep which sends results back one file at a time. It wouldn't be efficient for other search + // providers that send results in random order. We could do this step afterwards instead. + if (this._currentFileMatch && (this._currentFolderIdx !== folderIdx || !resources.isEqual(this._currentUri, data.uri))) { + this.pushToCollector(); + this._currentFileMatch = null; + } + + if (!this._currentFileMatch) { + this._currentFolderIdx = folderIdx; + this._currentFileMatch = { + resource: data.uri, + results: [] + }; + } + + this._currentFileMatch.results!.push(extensionResultToFrontendResult(data)); + } + + private pushToCollector(): void { + const size = this._currentFileMatch && this._currentFileMatch.results ? + this._currentFileMatch.results.length : + 0; + this._batchedCollector.addItem(this._currentFileMatch!, size); + } + + flush(): void { + this.pushToCollector(); + this._batchedCollector.flush(); + } + + private sendItems(items: IFileMatch[]): void { + this._onResult(items); + } +} + +function extensionResultToFrontendResult(data: TextSearchResult): ITextSearchResult { + // Warning: result from RipgrepTextSearchEH has fake Range. Don't depend on any other props beyond these... + if (extensionResultIsMatch(data)) { + return { + preview: { + matches: mapArrayOrNot(data.preview.matches, m => ({ + startLineNumber: m.start.line, + startColumn: m.start.character, + endLineNumber: m.end.line, + endColumn: m.end.character + })), + text: data.preview.text + }, + ranges: mapArrayOrNot(data.ranges, r => ({ + startLineNumber: r.start.line, + startColumn: r.start.character, + endLineNumber: r.end.line, + endColumn: r.end.character + })) + }; + } else { + return { + text: data.text, + lineNumber: data.lineNumber + }; + } +} + +export function extensionResultIsMatch(data: TextSearchResult): data is TextSearchMatch { + return !!(data).preview; +} + +/** + * Collects items that have a size - before the cumulative size of collected items reaches START_BATCH_AFTER_COUNT, the callback is called for every + * set of items collected. + * But after that point, the callback is called with batches of maxBatchSize. + * If the batch isn't filled within some time, the callback is also called. + */ +export class BatchedCollector { + private static readonly TIMEOUT = 4000; + + // After START_BATCH_AFTER_COUNT items have been collected, stop flushing on timeout + private static readonly START_BATCH_AFTER_COUNT = 50; + + private totalNumberCompleted = 0; + private batch: T[] = []; + private batchSize = 0; + private timeoutHandle: any; + + constructor(private maxBatchSize: number, private cb: (items: T[]) => void) { + } + + addItem(item: T, size: number): void { + if (!item) { + return; + } + + this.addItemToBatch(item, size); + } + + addItems(items: T[], size: number): void { + if (!items) { + return; + } + + this.addItemsToBatch(items, size); + } + + private addItemToBatch(item: T, size: number): void { + this.batch.push(item); + this.batchSize += size; + this.onUpdate(); + } + + private addItemsToBatch(item: T[], size: number): void { + this.batch = this.batch.concat(item); + this.batchSize += size; + this.onUpdate(); + } + + private onUpdate(): void { + if (this.totalNumberCompleted < BatchedCollector.START_BATCH_AFTER_COUNT) { + // Flush because we aren't batching yet + this.flush(); + } else if (this.batchSize >= this.maxBatchSize) { + // Flush because the batch is full + this.flush(); + } else if (!this.timeoutHandle) { + // No timeout running, start a timeout to flush + this.timeoutHandle = setTimeout(() => { + this.flush(); + }, BatchedCollector.TIMEOUT); + } + } + + flush(): void { + if (this.batchSize) { + this.totalNumberCompleted += this.batchSize; + this.cb(this.batch); + this.batch = []; + this.batchSize = 0; + + if (this.timeoutHandle) { + clearTimeout(this.timeoutHandle); + this.timeoutHandle = 0; + } + } + } +} diff --git a/src/vs/workbench/services/search/node/textSearchAdapter.ts b/src/vs/workbench/services/search/node/textSearchAdapter.ts index 37bca799785..5d7c484e3ca 100644 --- a/src/vs/workbench/services/search/node/textSearchAdapter.ts +++ b/src/vs/workbench/services/search/node/textSearchAdapter.ts @@ -7,12 +7,11 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import * as pfs from 'vs/base/node/pfs'; import { IFileMatch, IProgressMessage, ITextQuery, ITextSearchStats, ITextSearchMatch, ISerializedFileMatch, ISerializedSearchSuccess } from 'vs/workbench/services/search/common/search'; import { RipgrepTextSearchEngine } from 'vs/workbench/services/search/node/ripgrepTextSearchEngine'; -import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; +import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; export class TextSearchEngineAdapter { - constructor(private query: ITextQuery) { - } + constructor(private query: ITextQuery) { } search(token: CancellationToken, onResult: (matches: ISerializedFileMatch[]) => void, onMessage: (message: IProgressMessage) => void): Promise { if ((!this.query.folderQueries || !this.query.folderQueries.length) && (!this.query.extraFileResources || !this.query.extraFileResources.length)) { @@ -30,7 +29,7 @@ export class TextSearchEngineAdapter { onMessage({ message: msg }); } }; - const textSearchManager = new TextSearchManager(this.query, new RipgrepTextSearchEngine(pretendOutputChannel), pfs); + const textSearchManager = new NativeTextSearchManager(this.query, new RipgrepTextSearchEngine(pretendOutputChannel), pfs); return new Promise((resolve, reject) => { return textSearchManager .search( diff --git a/src/vs/workbench/services/search/node/textSearchManager.ts b/src/vs/workbench/services/search/node/textSearchManager.ts index e7586a912cd..3433ce35537 100644 --- a/src/vs/workbench/services/search/node/textSearchManager.ts +++ b/src/vs/workbench/services/search/node/textSearchManager.ts @@ -3,352 +3,18 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as path from 'vs/base/common/path'; -import { mapArrayOrNot } from 'vs/base/common/arrays'; -import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { toErrorMessage } from 'vs/base/common/errorMessage'; -import * as resources from 'vs/base/common/resources'; -import * as glob from 'vs/base/common/glob'; -import { URI } from 'vs/base/common/uri'; import { toCanonicalName } from 'vs/base/node/encoding'; import * as pfs from 'vs/base/node/pfs'; -import { IExtendedExtensionSearchOptions, IFileMatch, IFolderQuery, IPatternInfo, ISearchCompleteStats, ITextQuery, ITextSearchContext, ITextSearchMatch, ITextSearchResult, QueryGlobTester, resolvePatternsForProvider } from 'vs/workbench/services/search/common/search'; -import { TextSearchProvider, TextSearchResult, TextSearchMatch, TextSearchComplete, Range, TextSearchOptions, TextSearchQuery } from 'vs/workbench/services/search/common/searchExtTypes'; +import { ITextQuery } from 'vs/workbench/services/search/common/search'; +import { TextSearchProvider } from 'vs/workbench/services/search/common/searchExtTypes'; +import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager'; -export class TextSearchManager { +export class NativeTextSearchManager extends TextSearchManager { - private collector: TextSearchResultsCollector | null = null; - - private isLimitHit = false; - private resultCount = 0; - - constructor(private query: ITextQuery, private provider: TextSearchProvider, private _pfs: typeof pfs = pfs) { - } - - search(onProgress: (matches: IFileMatch[]) => void, token: CancellationToken): Promise { - const folderQueries = this.query.folderQueries || []; - const tokenSource = new CancellationTokenSource(); - token.onCancellationRequested(() => tokenSource.cancel()); - - return new Promise((resolve, reject) => { - this.collector = new TextSearchResultsCollector(onProgress); - - let isCanceled = false; - const onResult = (result: TextSearchResult, folderIdx: number) => { - if (isCanceled) { - return; - } - - if (!this.isLimitHit) { - const resultSize = this.resultSize(result); - if (extensionResultIsMatch(result) && typeof this.query.maxResults === 'number' && this.resultCount + resultSize > this.query.maxResults) { - this.isLimitHit = true; - isCanceled = true; - tokenSource.cancel(); - - result = this.trimResultToSize(result, this.query.maxResults - this.resultCount); - } - - const newResultSize = this.resultSize(result); - this.resultCount += newResultSize; - if (newResultSize > 0) { - this.collector!.add(result, folderIdx); - } - } - }; - - // For each root folder - Promise.all(folderQueries.map((fq, i) => { - return this.searchInFolder(fq, r => onResult(r, i), tokenSource.token); - })).then(results => { - tokenSource.dispose(); - this.collector!.flush(); - - const someFolderHitLImit = results.some(result => !!result && !!result.limitHit); - resolve({ - limitHit: this.isLimitHit || someFolderHitLImit, - stats: { - type: 'textSearchProvider' - } - }); - }, (err: Error) => { - tokenSource.dispose(); - const errMsg = toErrorMessage(err); - reject(new Error(errMsg)); - }); + constructor(query: ITextQuery, provider: TextSearchProvider, _pfs: typeof pfs = pfs) { + super(query, provider, { + readdir: resource => _pfs.readdir(resource.fsPath), + toCanonicalName: name => toCanonicalName(name) }); } - - private resultSize(result: TextSearchResult): number { - const match = result; - return Array.isArray(match.ranges) ? - match.ranges.length : - 1; - } - - private trimResultToSize(result: TextSearchMatch, size: number): TextSearchMatch { - const rangesArr = Array.isArray(result.ranges) ? result.ranges : [result.ranges]; - const matchesArr = Array.isArray(result.preview.matches) ? result.preview.matches : [result.preview.matches]; - - return { - ranges: rangesArr.slice(0, size), - preview: { - matches: matchesArr.slice(0, size), - text: result.preview.text - }, - uri: result.uri - }; - } - - private searchInFolder(folderQuery: IFolderQuery, onResult: (result: TextSearchResult) => void, token: CancellationToken): Promise { - const queryTester = new QueryGlobTester(this.query, folderQuery); - const testingPs: Promise[] = []; - const progress = { - report: (result: TextSearchResult) => { - if (!this.validateProviderResult(result)) { - return; - } - - const hasSibling = folderQuery.folder.scheme === 'file' ? - glob.hasSiblingPromiseFn(() => { - return this.readdir(path.dirname(result.uri.fsPath)); - }) : - undefined; - - const relativePath = path.relative(folderQuery.folder.fsPath, result.uri.fsPath); - testingPs.push( - queryTester.includedInQuery(relativePath, path.basename(relativePath), hasSibling) - .then(included => { - if (included) { - onResult(result); - } - })); - } - }; - - const searchOptions = this.getSearchOptionsForFolder(folderQuery); - return new Promise(resolve => process.nextTick(resolve)) - .then(() => this.provider.provideTextSearchResults(patternInfoToQuery(this.query.contentPattern), searchOptions, progress, token)) - .then(result => { - return Promise.all(testingPs) - .then(() => result); - }); - } - - private validateProviderResult(result: TextSearchResult): boolean { - if (extensionResultIsMatch(result)) { - if (Array.isArray(result.ranges)) { - if (!Array.isArray(result.preview.matches)) { - console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same type.'); - return false; - } - - if ((result.preview.matches).length !== result.ranges.length) { - console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same length.'); - return false; - } - } else { - if (Array.isArray(result.preview.matches)) { - console.warn('INVALID - A text search provider match\'s`ranges` and`matches` properties must have the same length.'); - return false; - } - } - } - - return true; - } - - private readdir(dirname: string): Promise { - return this._pfs.readdir(dirname); - } - - private getSearchOptionsForFolder(fq: IFolderQuery): TextSearchOptions { - const includes = resolvePatternsForProvider(this.query.includePattern, fq.includePattern); - const excludes = resolvePatternsForProvider(this.query.excludePattern, fq.excludePattern); - - const options = { - folder: URI.from(fq.folder), - excludes, - includes, - useIgnoreFiles: !fq.disregardIgnoreFiles, - useGlobalIgnoreFiles: !fq.disregardGlobalIgnoreFiles, - followSymlinks: !fq.ignoreSymlinks, - encoding: fq.fileEncoding && toCanonicalName(fq.fileEncoding), - maxFileSize: this.query.maxFileSize, - maxResults: this.query.maxResults, - previewOptions: this.query.previewOptions, - afterContext: this.query.afterContext, - beforeContext: this.query.beforeContext - }; - (options).usePCRE2 = this.query.usePCRE2; - return options; - } -} - -function patternInfoToQuery(patternInfo: IPatternInfo): TextSearchQuery { - return { - isCaseSensitive: patternInfo.isCaseSensitive || false, - isRegExp: patternInfo.isRegExp || false, - isWordMatch: patternInfo.isWordMatch || false, - isMultiline: patternInfo.isMultiline || false, - pattern: patternInfo.pattern - }; -} - -export class TextSearchResultsCollector { - private _batchedCollector: BatchedCollector; - - private _currentFolderIdx: number = -1; - private _currentUri: URI | undefined; - private _currentFileMatch: IFileMatch | null = null; - - constructor(private _onResult: (result: IFileMatch[]) => void) { - this._batchedCollector = new BatchedCollector(512, items => this.sendItems(items)); - } - - add(data: TextSearchResult, folderIdx: number): void { - // Collects TextSearchResults into IInternalFileMatches and collates using BatchedCollector. - // This is efficient for ripgrep which sends results back one file at a time. It wouldn't be efficient for other search - // providers that send results in random order. We could do this step afterwards instead. - if (this._currentFileMatch && (this._currentFolderIdx !== folderIdx || !resources.isEqual(this._currentUri, data.uri))) { - this.pushToCollector(); - this._currentFileMatch = null; - } - - if (!this._currentFileMatch) { - this._currentFolderIdx = folderIdx; - this._currentFileMatch = { - resource: data.uri, - results: [] - }; - } - - this._currentFileMatch.results!.push(extensionResultToFrontendResult(data)); - } - - private pushToCollector(): void { - const size = this._currentFileMatch && this._currentFileMatch.results ? - this._currentFileMatch.results.length : - 0; - this._batchedCollector.addItem(this._currentFileMatch!, size); - } - - flush(): void { - this.pushToCollector(); - this._batchedCollector.flush(); - } - - private sendItems(items: IFileMatch[]): void { - this._onResult(items); - } -} - -function extensionResultToFrontendResult(data: TextSearchResult): ITextSearchResult { - // Warning: result from RipgrepTextSearchEH has fake Range. Don't depend on any other props beyond these... - if (extensionResultIsMatch(data)) { - return { - preview: { - matches: mapArrayOrNot(data.preview.matches, m => ({ - startLineNumber: m.start.line, - startColumn: m.start.character, - endLineNumber: m.end.line, - endColumn: m.end.character - })), - text: data.preview.text - }, - ranges: mapArrayOrNot(data.ranges, r => ({ - startLineNumber: r.start.line, - startColumn: r.start.character, - endLineNumber: r.end.line, - endColumn: r.end.character - })) - }; - } else { - return { - text: data.text, - lineNumber: data.lineNumber - }; - } -} - -export function extensionResultIsMatch(data: TextSearchResult): data is TextSearchMatch { - return !!(data).preview; -} - -/** - * Collects items that have a size - before the cumulative size of collected items reaches START_BATCH_AFTER_COUNT, the callback is called for every - * set of items collected. - * But after that point, the callback is called with batches of maxBatchSize. - * If the batch isn't filled within some time, the callback is also called. - */ -export class BatchedCollector { - private static readonly TIMEOUT = 4000; - - // After START_BATCH_AFTER_COUNT items have been collected, stop flushing on timeout - private static readonly START_BATCH_AFTER_COUNT = 50; - - private totalNumberCompleted = 0; - private batch: T[] = []; - private batchSize = 0; - private timeoutHandle: any; - - constructor(private maxBatchSize: number, private cb: (items: T[]) => void) { - } - - addItem(item: T, size: number): void { - if (!item) { - return; - } - - this.addItemToBatch(item, size); - } - - addItems(items: T[], size: number): void { - if (!items) { - return; - } - - this.addItemsToBatch(items, size); - } - - private addItemToBatch(item: T, size: number): void { - this.batch.push(item); - this.batchSize += size; - this.onUpdate(); - } - - private addItemsToBatch(item: T[], size: number): void { - this.batch = this.batch.concat(item); - this.batchSize += size; - this.onUpdate(); - } - - private onUpdate(): void { - if (this.totalNumberCompleted < BatchedCollector.START_BATCH_AFTER_COUNT) { - // Flush because we aren't batching yet - this.flush(); - } else if (this.batchSize >= this.maxBatchSize) { - // Flush because the batch is full - this.flush(); - } else if (!this.timeoutHandle) { - // No timeout running, start a timeout to flush - this.timeoutHandle = setTimeout(() => { - this.flush(); - }, BatchedCollector.TIMEOUT); - } - } - - flush(): void { - if (this.batchSize) { - this.totalNumberCompleted += this.batchSize; - this.cb(this.batch); - this.batch = []; - this.batchSize = 0; - - if (this.timeoutHandle) { - clearTimeout(this.timeoutHandle); - this.timeoutHandle = 0; - } - } - } } diff --git a/src/vs/workbench/services/search/test/node/textSearchManager.test.ts b/src/vs/workbench/services/search/test/node/textSearchManager.test.ts index 1efabf6224d..fec67730fa0 100644 --- a/src/vs/workbench/services/search/test/node/textSearchManager.test.ts +++ b/src/vs/workbench/services/search/test/node/textSearchManager.test.ts @@ -9,9 +9,9 @@ import { URI } from 'vs/base/common/uri'; import { Progress } from 'vs/platform/progress/common/progress'; import { ITextQuery, QueryType } from 'vs/workbench/services/search/common/search'; import { ProviderResult, TextSearchComplete, TextSearchOptions, TextSearchProvider, TextSearchQuery, TextSearchResult } from 'vs/workbench/services/search/common/searchExtTypes'; -import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; +import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; -suite('TextSearchManager', () => { +suite('NativeTextSearchManager', () => { test('fixes encoding', async () => { let correctEncoding = false; const provider: TextSearchProvider = { @@ -33,7 +33,7 @@ suite('TextSearchManager', () => { }] }; - const m = new TextSearchManager(query, provider); + const m = new NativeTextSearchManager(query, provider); await m.search(() => { }, new CancellationTokenSource().token); assert.ok(correctEncoding); diff --git a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts index cb553b6fcc8..dc9222e4b02 100644 --- a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts +++ b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts @@ -22,7 +22,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { ITMSyntaxExtensionPoint, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; -import { ITokenColorizationRule, IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { ITextMateThemingRule, IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IGrammar, StackElement, IOnigLib, IRawTheme } from 'vscode-textmate'; import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -257,7 +257,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex TokenizationRegistry.setColorMap(colorMap); } - private static equalsTokenRules(a: ITokenColorizationRule[] | null, b: ITokenColorizationRule[] | null): boolean { + private static equalsTokenRules(a: ITextMateThemingRule[] | null, b: ITextMateThemingRule[] | null): boolean { if (!b || !a || b.length !== a.length) { return false; } diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index b77eb7be4c0..ea66d626d2e 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -9,11 +9,11 @@ import * as objects from 'vs/base/common/objects'; import { Emitter, AsyncEmitter } from 'vs/base/common/event'; import * as platform from 'vs/base/common/platform'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, IAutoSaveConfiguration, AutoSaveMode, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, AutoSaveContext, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; +import { IResult, ITextFileOperationResult, ITextFileService, ITextFileStreamContent, SaveReason, ITextFileEditorModelManager, ITextFileEditorModel, ModelState, ISaveOptions, ITextFileContent, IResourceEncodings, IReadTextFileOptions, IWriteTextFileOptions, toBufferOrReadable, TextFileOperationError, TextFileOperationResult, FileOperationWillRunEvent, FileOperationDidRunEvent } from 'vs/workbench/services/textfile/common/textfiles'; import { ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; import { ILifecycleService, ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; -import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, AutoSaveConfiguration, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; +import { IFileService, IFilesConfiguration, FileOperationError, FileOperationResult, HotExitConfiguration, IFileStatWithMetadata, ICreateFileOptions, FileOperation } from 'vs/platform/files/common/files'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable } from 'vs/base/common/lifecycle'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; @@ -24,7 +24,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { ResourceMap } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; import { IModelService } from 'vs/editor/common/services/modelService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -38,6 +37,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { ITextSnapshot } from 'vs/editor/common/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; +import { IAutoSaveConfigurationService, AutoSaveMode } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -48,9 +48,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region events - private readonly _onAutoSaveConfigurationChange = this._register(new Emitter()); - readonly onAutoSaveConfigurationChange = this._onAutoSaveConfigurationChange.event; - private readonly _onFilesAssociationChange = this._register(new Emitter()); readonly onFilesAssociationChange = this._onFilesAssociationChange.event; @@ -68,11 +65,8 @@ export abstract class AbstractTextFileService extends Disposable implements ITex abstract get encoding(): IResourceEncodings; private currentFilesAssociationConfig: { [key: string]: string; }; - private configuredAutoSaveDelay?: number; - private configuredAutoSaveOnFocusChange: boolean | undefined; - private configuredAutoSaveOnWindowChange: boolean | undefined; + private configuredHotExit: string | undefined; - private autoSaveContext: IContextKey; constructor( @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @@ -87,22 +81,19 @@ export abstract class AbstractTextFileService extends Disposable implements ITex @INotificationService private readonly notificationService: INotificationService, @IBackupFileService private readonly backupFileService: IBackupFileService, @IHistoryService private readonly historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService private readonly dialogService: IDialogService, @IFileDialogService private readonly fileDialogService: IFileDialogService, @IEditorService private readonly editorService: IEditorService, - @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService + @ITextResourceConfigurationService protected readonly textResourceConfigurationService: ITextResourceConfigurationService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(); this._models = this._register(instantiationService.createInstance(TextFileEditorModelManager)); - this.autoSaveContext = AutoSaveContext.bindTo(contextKeyService); const configuration = configurationService.getValue(); this.currentFilesAssociationConfig = configuration?.files?.associations; - this.onFilesConfigurationChange(configuration); - this.registerListeners(); } @@ -120,6 +111,17 @@ export abstract class AbstractTextFileService extends Disposable implements ITex this.onFilesConfigurationChange(this.configurationService.getValue()); } })); + + // Auto save changes + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(() => this.onAutoSaveConfigurationChange())); + } + + private onAutoSaveConfigurationChange(): void { + + // save all dirty when enabling auto save + if (this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { + this.saveAll(); + } } protected onBeforeShutdown(reason: ShutdownReason): boolean | Promise { @@ -130,7 +132,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // If auto save is enabled, save all files and then check again for dirty files // We DO NOT run any save participant if we are in the shutdown phase for performance reasons - if (this.getAutoSaveMode() !== AutoSaveMode.OFF) { + if (this.autoSaveConfigurationService.getAutoSaveMode() !== AutoSaveMode.OFF) { return this.saveAll(false /* files only */, { skipSaveParticipants: true }).then(() => { // If we still have dirty files, we either have untitled ones or files that cannot be saved @@ -302,43 +304,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex } protected onFilesConfigurationChange(configuration: IFilesConfiguration): void { - const wasAutoSaveEnabled = (this.getAutoSaveMode() !== AutoSaveMode.OFF); - - const autoSaveMode = configuration?.files?.autoSave || AutoSaveConfiguration.OFF; - this.autoSaveContext.set(autoSaveMode); - switch (autoSaveMode) { - case AutoSaveConfiguration.AFTER_DELAY: - this.configuredAutoSaveDelay = configuration?.files?.autoSaveDelay; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = false; - break; - - case AutoSaveConfiguration.ON_FOCUS_CHANGE: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = true; - this.configuredAutoSaveOnWindowChange = false; - break; - - case AutoSaveConfiguration.ON_WINDOW_CHANGE: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = true; - break; - - default: - this.configuredAutoSaveDelay = undefined; - this.configuredAutoSaveOnFocusChange = false; - this.configuredAutoSaveOnWindowChange = false; - break; - } - - // Emit as event - this._onAutoSaveConfigurationChange.fire(this.getAutoSaveConfiguration()); - - // save all dirty when enabling auto save - if (!wasAutoSaveEnabled && this.getAutoSaveMode() !== AutoSaveMode.OFF) { - this.saveAll(); - } // Check for change in files associations const filesAssociation = configuration?.files?.associations; @@ -467,7 +432,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex const sourceModels: ITextFileEditorModel[] = []; const conflictingModels: ITextFileEditorModel[] = []; for (const model of this.getFileModels()) { - const resource = model.getResource(); + const resource = model.resource; if (isEqualOrParent(resource, target, false /* do not ignorecase, see https://github.com/Microsoft/vscode/issues/56384 */)) { conflictingModels.push(model); @@ -483,7 +448,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex type ModelToRestore = { resource: URI; snapshot?: ITextSnapshot }; const modelsToRestore: ModelToRestore[] = []; for (const sourceModel of sourceModels) { - const sourceModelResource = sourceModel.getResource(); + const sourceModelResource = sourceModel.resource; // If the source is the actual model, just use target as new resource let modelToRestoreResource: URI; @@ -508,7 +473,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // in order to move, we need to soft revert all dirty models, // both from the source as well as the target if any const dirtyModels = [...sourceModels, ...conflictingModels].filter(model => model.isDirty()); - await this.revertAll(dirtyModels.map(dirtyModel => dirtyModel.getResource()), { soft: true }); + await this.revertAll(dirtyModels.map(dirtyModel => dirtyModel.resource), { soft: true }); // now we can rename the source to target via file operation let stat: IFileStatWithMetadata; @@ -735,9 +700,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex }); const mapResourceToResult = new ResourceMap(); - dirtyFileModels.forEach(m => { - mapResourceToResult.set(m.getResource(), { - source: m.getResource() + dirtyFileModels.forEach(dirtyModel => { + mapResourceToResult.set(dirtyModel.resource, { + source: dirtyModel.resource }); }); @@ -745,7 +710,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex await model.save(options); if (!model.isDirty()) { - const result = mapResourceToResult.get(model.getResource()); + const result = mapResourceToResult.get(model.resource); if (result) { result.success = true; } @@ -861,7 +826,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // path. This can happen if the file was created after the untitled file was opened. // See https://github.com/Microsoft/vscode/issues/67946 let write: boolean; - if (sourceModel instanceof UntitledTextEditorModel && sourceModel.hasAssociatedFilePath && targetExists && isEqual(target, toLocalResource(sourceModel.getResource(), this.environmentService.configuration.remoteAuthority))) { + if (sourceModel instanceof UntitledTextEditorModel && sourceModel.hasAssociatedFilePath && targetExists && isEqual(target, toLocalResource(sourceModel.resource, this.environmentService.configuration.remoteAuthority))) { write = await this.confirmOverwrite(target); } else { write = true; @@ -944,9 +909,9 @@ export abstract class AbstractTextFileService extends Disposable implements ITex const fileModels = options?.force ? this.getFileModels(resources) : this.getDirtyFileModels(resources); const mapResourceToResult = new ResourceMap(); - fileModels.forEach(m => { - mapResourceToResult.set(m.getResource(), { - source: m.getResource() + fileModels.forEach(fileModel => { + mapResourceToResult.set(fileModel.resource, { + source: fileModel.resource }); }); @@ -955,7 +920,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex await model.revert(options?.soft); if (!model.isDirty()) { - const result = mapResourceToResult.get(model.getResource()); + const result = mapResourceToResult.get(model.resource); if (result) { result.success = true; } @@ -964,7 +929,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex // FileNotFound means the file got deleted meanwhile, so still record as successful revert if ((error).fileOperationResult === FileOperationResult.FILE_NOT_FOUND) { - const result = mapResourceToResult.get(model.getResource()); + const result = mapResourceToResult.get(model.resource); if (result) { result.success = true; } @@ -983,7 +948,7 @@ export abstract class AbstractTextFileService extends Disposable implements ITex getDirty(resources?: URI[]): URI[] { // Collect files - const dirty = this.getDirtyFileModels(resources).map(m => m.getResource()); + const dirty = this.getDirtyFileModels(resources).map(dirtyFileModel => dirtyFileModel.resource); // Add untitled ones dirty.push(...this.untitledTextEditorService.getDirty(resources)); @@ -1006,30 +971,6 @@ export abstract class AbstractTextFileService extends Disposable implements ITex //#region config - getAutoSaveMode(): AutoSaveMode { - if (this.configuredAutoSaveOnFocusChange) { - return AutoSaveMode.ON_FOCUS_CHANGE; - } - - if (this.configuredAutoSaveOnWindowChange) { - return AutoSaveMode.ON_WINDOW_CHANGE; - } - - if (this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0) { - return this.configuredAutoSaveDelay <= 1000 ? AutoSaveMode.AFTER_SHORT_DELAY : AutoSaveMode.AFTER_LONG_DELAY; - } - - return AutoSaveMode.OFF; - } - - getAutoSaveConfiguration(): IAutoSaveConfiguration { - return { - autoSaveDelay: this.configuredAutoSaveDelay && this.configuredAutoSaveDelay > 0 ? this.configuredAutoSaveDelay : undefined, - autoSaveFocusChange: !!this.configuredAutoSaveOnFocusChange, - autoSaveApplicationChange: !!this.configuredAutoSaveOnWindowChange - }; - } - get isHotExitEnabled(): boolean { return !this.environmentService.isExtensionDevelopment && this.configuredHotExit !== HotExitConfiguration.OFF; } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 5cfaec6676b..c50d7ea0404 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Emitter } from 'vs/base/common/event'; import { guessMimeTypes } from 'vs/base/common/mime'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { URI } from 'vs/base/common/uri'; import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; import { EncodingMode } from 'vs/workbench/common/editor'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; @@ -29,9 +29,12 @@ import { ILogService } from 'vs/platform/log/common/log'; import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/common/resources'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; +import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, IAutoSaveConfiguration } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export interface IBackupMetaData { mtime: number; + ctime: number; size: number; etag: string; orphaned: boolean; @@ -69,11 +72,16 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private static saveParticipant: ISaveParticipant | null; static setSaveParticipant(handler: ISaveParticipant | null): void { TextFileEditorModel.saveParticipant = handler; } - private readonly _onDidContentChange: Emitter = this._register(new Emitter()); - readonly onDidContentChange: Event = this._onDidContentChange.event; + private readonly _onDidContentChange = this._register(new Emitter()); + readonly onDidContentChange = this._onDidContentChange.event; - private readonly _onDidStateChange: Emitter = this._register(new Emitter()); - readonly onDidStateChange: Event = this._onDidStateChange.event; + private readonly _onDidStateChange = this._register(new Emitter()); + readonly onDidStateChange = this._onDidStateChange.event; + + private readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; + + readonly capabilities = WorkingCopyCapabilities.AutoSave; private contentEncoding: string | undefined; // encoding as reported from disk @@ -100,7 +108,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil private disposed = false; constructor( - private readonly resource: URI, + public readonly resource: URI, private preferredEncoding: string | undefined, // encoding as chosen by the user private preferredMode: string | undefined, // mode as chosen by the user @INotificationService private readonly notificationService: INotificationService, @@ -113,18 +121,23 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil @IBackupFileService private readonly backupFileService: IBackupFileService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IWorkingCopyService private readonly workingCopyService: IWorkingCopyService, + @IAutoSaveConfigurationService private readonly autoSaveConfigurationService: IAutoSaveConfigurationService ) { super(modelService, modeService); - this.updateAutoSaveConfiguration(textFileService.getAutoSaveConfiguration()); + this.updateAutoSaveConfiguration(autoSaveConfigurationService.getAutoSaveConfiguration()); + + // Make known to working copy service + this._register(this.workingCopyService.registerWorkingCopy(this)); this.registerListeners(); } private registerListeners(): void { this._register(this.fileService.onFileChanges(e => this.onFileChanges(e))); - this._register(this.textFileService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); + this._register(this.autoSaveConfigurationService.onAutoSaveConfigurationChange(config => this.updateAutoSaveConfiguration(config))); this._register(this.textFileService.onFilesAssociationChange(e => this.onFilesAssociationChange())); this._register(this.onDidStateChange(e => this.onStateChange(e))); } @@ -224,6 +237,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (isEqual(target, this.resource) && this.lastResolvedFileStat) { meta = { mtime: this.lastResolvedFileStat.mtime, + ctime: this.lastResolvedFileStat.ctime, size: this.lastResolvedFileStat.size, etag: this.lastResolvedFileStat.etag, orphaned: this.inOrphanMode @@ -247,6 +261,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.autoSaveDisposable.clear(); // Unset flags + const wasDirty = this.dirty; const undo = this.setDirty(false); // Force read from disk unless reverting soft @@ -264,6 +279,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Emit file change event this._onDidStateChange.fire(StateChange.REVERTED); + + // Emit dirty change event + if (wasDirty) { + this._onDidChangeDirty.fire(); + } } async load(options?: ILoadOptions): Promise { @@ -313,6 +333,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil resource: this.resource, name: basename(this.resource), mtime: resolvedBackup.meta ? resolvedBackup.meta.mtime : Date.now(), + ctime: resolvedBackup.meta ? resolvedBackup.meta.ctime : Date.now(), size: resolvedBackup.meta ? resolvedBackup.meta.size : 0, etag: resolvedBackup.meta ? resolvedBackup.meta.etag : ETAG_DISABLED, // etag disabled if unknown! value: resolvedBackup.value, @@ -397,8 +418,10 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil resource: this.resource, name: content.name, mtime: content.mtime, + ctime: content.ctime, size: content.size, etag: content.etag, + isFile: true, isDirectory: false, isSymbolicLink: false, isReadonly: content.isReadonly @@ -523,6 +546,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Emit event if (wasDirty) { this._onDidStateChange.fire(StateChange.REVERTED); + this._onDidChangeDirty.fire(); } return; @@ -563,6 +587,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Emit as Event if we turned dirty if (!wasDirty) { this._onDidStateChange.fire(StateChange.DIRTY); + this._onDidChangeDirty.fire(); } } @@ -734,8 +759,9 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Cancel any content change event promises as they are no longer valid this.contentChangeEventScheduler.cancel(); - // Emit File Saved Event + // Emit Events this._onDidStateChange.fire(StateChange.SAVED); + this._onDidChangeDirty.fire(); // Telemetry const settingsType = this.getTypeIfSettings(); @@ -1006,10 +1032,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.disposed; } - getResource(): URI { - return this.resource; - } - getStat(): IFileStatWithMetadata | undefined { return this.lastResolvedFileStat; } @@ -1120,6 +1142,6 @@ class DefaultSaveErrorHandler implements ISaveErrorHandler { constructor(@INotificationService private readonly notificationService: INotificationService) { } onSaveError(error: Error, model: TextFileEditorModel): void { - this.notificationService.error(nls.localize('genericSaveError', "Failed to save '{0}': {1}", basename(model.getResource()), toErrorMessage(error, false))); + this.notificationService.error(nls.localize('genericSaveError', "Failed to save '{0}': {1}", basename(model.resource), toErrorMessage(error, false))); } } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 562aa4c727e..08ebc5edc4d 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -304,7 +304,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE return; // already disposed } - if (this.mapResourceToPendingModelLoaders.has(model.getResource())) { + if (this.mapResourceToPendingModelLoaders.has(model.resource)) { return; // not yet loaded } diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 5a752b20128..93414127020 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -11,10 +11,10 @@ import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteF import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { ITextBufferFactory, ITextModel, ITextSnapshot } from 'vs/editor/common/model'; -import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { isNative } from 'vs/base/common/platform'; +import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export const ITextFileService = createDecorator('textFileService'); @@ -22,8 +22,6 @@ export interface ITextFileService extends IDisposable { _serviceBrand: undefined; - readonly onAutoSaveConfigurationChange: Event; - readonly onFilesAssociationChange: Event; readonly isHotExitEnabled: boolean; @@ -143,16 +141,6 @@ export interface ITextFileService extends IDisposable { * confirming for all dirty resources. */ confirmSave(resources?: URI[]): Promise; - - /** - * Convenient fast access to the current auto save mode. - */ - getAutoSaveMode(): AutoSaveMode; - - /** - * Convenient fast access to the raw configured auto save settings. - */ - getAutoSaveConfiguration(): IAutoSaveConfiguration; } @@ -328,7 +316,7 @@ export class TextFileModelChangeEvent { private _resource: URI; constructor(model: ITextFileEditorModel, private _kind: StateChange) { - this._resource = model.getResource(); + this._resource = model.resource; } get resource(): URI { @@ -340,8 +328,6 @@ export class TextFileModelChangeEvent { } } -export const AutoSaveContext = new RawContextKey('config.files.autoSave', undefined); - export interface ITextFileOperationResult { results: IResult[]; } @@ -352,20 +338,6 @@ export interface IResult { success?: boolean; } -export interface IAutoSaveConfiguration { - autoSaveDelay?: number; - autoSaveFocusChange: boolean; - autoSaveApplicationChange: boolean; -} - -export const enum AutoSaveMode { - OFF, - AFTER_SHORT_DELAY, - AFTER_LONG_DELAY, - ON_FOCUS_CHANGE, - ON_WINDOW_CHANGE -} - export const enum SaveReason { EXPLICIT = 1, AUTO = 2, @@ -492,13 +464,11 @@ export interface ILoadOptions { reason?: LoadReason; } -export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, IModeSupport { +export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, IModeSupport, IWorkingCopy { readonly onDidContentChange: Event; readonly onDidStateChange: Event; - getResource(): URI; - hasState(state: ModelState): boolean; updatePreferredEncoding(encoding: string | undefined): void; diff --git a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts index 23cf1f058dc..3a1487ec779 100644 --- a/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/nativeTextFileService.ts @@ -38,11 +38,11 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { INotificationService } from 'vs/platform/notification/common/notification'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IHistoryService } from 'vs/workbench/services/history/common/history'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IDialogService, IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ConfirmResult } from 'vs/workbench/common/editor'; import { assign } from 'vs/base/common/objects'; +import { IAutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export class NativeTextFileService extends AbstractTextFileService { @@ -59,15 +59,15 @@ export class NativeTextFileService extends AbstractTextFileService { @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, @IHistoryService historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @IEditorService editorService: IEditorService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IElectronService private readonly electronService: IElectronService, - @IProductService private readonly productService: IProductService + @IProductService private readonly productService: IProductService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { - super(contextService, fileService, untitledTextEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, contextKeyService, dialogService, fileDialogService, editorService, textResourceConfigurationService); + super(contextService, fileService, untitledTextEditorService, lifecycleService, instantiationService, configurationService, modeService, modelService, environmentService, notificationService, backupFileService, historyService, dialogService, fileDialogService, editorService, textResourceConfigurationService, autoSaveConfigurationService); } private _encoding: EncodingOracle | undefined; diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index 07c3271fa95..8ccf5a25c5d 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -16,9 +16,15 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { timeout } from 'vs/base/common/async'; import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; import { assertIsDefined } from 'vs/base/common/types'; +import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; class ServiceAccessor { - constructor(@ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService, @IFileService public fileService: TestFileService) { + constructor( + @ITextFileService public readonly textFileService: TestTextFileService, + @IModelService public readonly modelService: IModelService, + @IFileService public readonly fileService: TestFileService, + @IWorkingCopyService public readonly workingCopyService: IWorkingCopyService + ) { } } @@ -51,10 +57,15 @@ suite('Files - TextFileEditorModel', () => { await model.load(); + assert.equal(accessor.workingCopyService.dirtyCount, 0); + model.textEditorModel!.setValue('bar'); assert.ok(getLastModifiedTime(model) <= Date.now()); assert.ok(model.hasState(ModelState.DIRTY)); + assert.equal(accessor.workingCopyService.dirtyCount, 1); + assert.equal(accessor.workingCopyService.isDirty(model.resource), true); + let savedEvent = false; model.onDidStateChange(e => { if (e === StateChange.SAVED) { @@ -62,6 +73,13 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + const pendingSave = model.save(); assert.ok(model.hasState(ModelState.PENDING_SAVE)); @@ -71,9 +89,13 @@ suite('Files - TextFileEditorModel', () => { assert.ok(model.hasState(ModelState.SAVED)); assert.ok(!model.isDirty()); assert.ok(savedEvent); + assert.ok(workingCopyEvent); + + assert.equal(accessor.workingCopyService.dirtyCount, 0); + assert.equal(accessor.workingCopyService.isDirty(model.resource), false); model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); }); test('save - touching also emits saved event', async function () { @@ -88,12 +110,20 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + await model.save({ force: true }); assert.ok(savedEvent); + assert.ok(!workingCopyEvent); model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); }); test('setEncoding - encode', function () { @@ -132,7 +162,7 @@ suite('Files - TextFileEditorModel', () => { assert.equal(model.textEditorModel!.getModeId(), mode); model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); }); test('disposes when underlying model is destroyed', async function () { @@ -155,7 +185,7 @@ suite('Files - TextFileEditorModel', () => { await model.load(); assert.ok(model.isResolved()); model.dispose(); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); }); test('Load returns dirty model as long as model is dirty', async function () { @@ -182,14 +212,29 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + await model.load(); model.textEditorModel!.setValue('foo'); assert.ok(model.isDirty()); + assert.equal(accessor.workingCopyService.dirtyCount, 1); + assert.equal(accessor.workingCopyService.isDirty(model.resource), true); + await model.revert(); assert.ok(!model.isDirty()); assert.equal(model.textEditorModel!.getValue(), 'Hello Html'); assert.equal(eventCounter, 1); + + assert.ok(workingCopyEvent); + assert.equal(accessor.workingCopyService.dirtyCount, 0); + assert.equal(accessor.workingCopyService.isDirty(model.resource), false); + model.dispose(); }); @@ -204,14 +249,29 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + await model.load(); model.textEditorModel!.setValue('foo'); assert.ok(model.isDirty()); + assert.equal(accessor.workingCopyService.dirtyCount, 1); + assert.equal(accessor.workingCopyService.isDirty(model.resource), true); + await model.revert(true /* soft revert */); assert.ok(!model.isDirty()); assert.equal(model.textEditorModel!.getValue(), 'foo'); assert.equal(eventCounter, 1); + + assert.ok(workingCopyEvent); + assert.equal(accessor.workingCopyService.dirtyCount, 0); + assert.equal(accessor.workingCopyService.isDirty(model.resource), false); + model.dispose(); }); @@ -223,6 +283,9 @@ suite('Files - TextFileEditorModel', () => { await model.load(); model.textEditorModel!.undo(); assert.ok(model.isDirty()); + + assert.equal(accessor.workingCopyService.dirtyCount, 1); + assert.equal(accessor.workingCopyService.isDirty(model.resource), true); }); test('Make Dirty', async function () { @@ -246,9 +309,18 @@ suite('Files - TextFileEditorModel', () => { } }); + let workingCopyEvent = false; + accessor.workingCopyService.onDidChangeDirty(e => { + if (e.resource.toString() === model.resource.toString()) { + workingCopyEvent = true; + } + }); + model.makeDirty(); assert.ok(model.isDirty()); assert.equal(eventCounter, 1); + assert.ok(workingCopyEvent); + model.dispose(); }); @@ -343,7 +415,6 @@ suite('Files - TextFileEditorModel', () => { }); test('Save Participant, async participant', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); TextFileEditorModel.setSaveParticipant({ diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index 857096d4b0d..0494cbf139b 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -273,7 +273,7 @@ suite('Files - TextFileEditorModelManager', () => { const model = await manager.loadOrCreate(resource, { encoding: 'utf8' }); model.dispose(); assert.ok(!manager.get(resource)); - assert.ok(!accessor.modelService.getModel(model.getResource())); + assert.ok(!accessor.modelService.getModel(model.resource)); manager.dispose(); }); diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index d8f09e50b79..fc486b3c0b7 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -67,7 +67,7 @@ suite('Files - TextFileService', () => { test('confirm onWillShutdown - no veto', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const event = new BeforeShutdownEventImpl(); accessor.lifecycleService.fireWillShutdown(event); @@ -82,7 +82,7 @@ suite('Files - TextFileService', () => { test('confirm onWillShutdown - veto if user cancels', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.CANCEL); @@ -98,7 +98,7 @@ suite('Files - TextFileService', () => { test('confirm onWillShutdown - no veto and backups cleaned up if user does not want to save (hot.exit: off)', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.DONT_SAVE); @@ -124,7 +124,7 @@ suite('Files - TextFileService', () => { test('confirm onWillShutdown - save (hot.exit: off)', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; service.setConfirmResult(ConfirmResult.SAVE); @@ -143,18 +143,18 @@ suite('Files - TextFileService', () => { test('isDirty/getDirty - files and untitled', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; await model.load(); - assert.ok(!service.isDirty(model.getResource())); + assert.ok(!service.isDirty(model.resource)); model.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); assert.equal(service.getDirty().length, 1); - assert.equal(service.getDirty([model.getResource()])[0].toString(), model.getResource().toString()); + assert.equal(service.getDirty([model.resource])[0].toString(), model.resource.toString()); const untitled = accessor.untitledTextEditorService.createOrGet(); const untitledModel = await untitled.resolve(); @@ -170,23 +170,23 @@ suite('Files - TextFileService', () => { test('save - file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; await model.load(); model.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - const res = await service.save(model.getResource()); + const res = await service.save(model.resource); assert.ok(res); - assert.ok(!service.isDirty(model.getResource())); + assert.ok(!service.isDirty(model.resource)); }); test('save - UNC path', async function () { const untitledUncUri = URI.from({ scheme: 'untitled', authority: 'server', path: '/share/path/file.txt' }); model = instantiationService.createInstance(TextFileEditorModel, untitledUncUri, 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const mockedFileUri = untitledUncUri.with({ scheme: Schemas.file }); const mockedEditorInput = instantiationService.createInstance(TextFileEditorModel, mockedFileUri, 'utf8', undefined); @@ -210,65 +210,65 @@ suite('Files - TextFileService', () => { test('saveAll - file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; await model.load(); model.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - const res = await service.saveAll([model.getResource()]); + const res = await service.saveAll([model.resource]); assert.ok(res); - assert.ok(!service.isDirty(model.getResource())); + assert.ok(!service.isDirty(model.resource)); assert.equal(res.results.length, 1); - assert.equal(res.results[0].source.toString(), model.getResource().toString()); + assert.equal(res.results[0].source.toString(), model.resource.toString()); }); test('saveAs - file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; - service.setPromptPath(model.getResource()); + service.setPromptPath(model.resource); await model.load(); model.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - const res = await service.saveAs(model.getResource()); - assert.equal(res!.toString(), model.getResource().toString()); - assert.ok(!service.isDirty(model.getResource())); + const res = await service.saveAs(model.resource); + assert.equal(res!.toString(), model.resource.toString()); + assert.ok(!service.isDirty(model.resource)); }); test('revert - file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; - service.setPromptPath(model.getResource()); + service.setPromptPath(model.resource); await model.load(); model!.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - const res = await service.revert(model.getResource()); + const res = await service.revert(model.resource); assert.ok(res); - assert.ok(!service.isDirty(model.getResource())); + assert.ok(!service.isDirty(model.resource)); }); test('delete - dirty file', async function () { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; await model.load(); model!.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(model.getResource())); + assert.ok(service.isDirty(model.resource)); - await service.delete(model.getResource()); - assert.ok(!service.isDirty(model.getResource())); + await service.delete(model.resource); + assert.ok(!service.isDirty(model.resource)); }); test('move - dirty file', async function () { @@ -282,27 +282,27 @@ suite('Files - TextFileService', () => { async function testMove(source: URI, target: URI, targetDirty?: boolean): Promise { let sourceModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, source, 'utf8', undefined); let targetModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, target, 'utf8', undefined); - (accessor.textFileService.models).add(sourceModel.getResource(), sourceModel); - (accessor.textFileService.models).add(targetModel.getResource(), targetModel); + (accessor.textFileService.models).add(sourceModel.resource, sourceModel); + (accessor.textFileService.models).add(targetModel.resource, targetModel); const service = accessor.textFileService; await sourceModel.load(); sourceModel.textEditorModel!.setValue('foo'); - assert.ok(service.isDirty(sourceModel.getResource())); + assert.ok(service.isDirty(sourceModel.resource)); if (targetDirty) { await targetModel.load(); targetModel.textEditorModel!.setValue('bar'); - assert.ok(service.isDirty(targetModel.getResource())); + assert.ok(service.isDirty(targetModel.resource)); } - await service.move(sourceModel.getResource(), targetModel.getResource(), true); + await service.move(sourceModel.resource, targetModel.resource, true); assert.equal(targetModel.textEditorModel!.getValue(), 'foo'); - assert.ok(!service.isDirty(sourceModel.getResource())); - assert.ok(service.isDirty(targetModel.getResource())); + assert.ok(!service.isDirty(sourceModel.resource)); + assert.ok(service.isDirty(targetModel.resource)); sourceModel.dispose(); targetModel.dispose(); @@ -413,7 +413,7 @@ suite('Files - TextFileService', () => { async function hotExitTest(this: any, setting: string, shutdownReason: ShutdownReason, multipleWindows: boolean, workspace: true, shouldVeto: boolean): Promise { model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(model.getResource(), model); + (accessor.textFileService.models).add(model.resource, model); const service = accessor.textFileService; // Set hot exit config diff --git a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts index a404c7e86e5..3ffe921e4cf 100644 --- a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts +++ b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts @@ -88,11 +88,11 @@ suite('Workbench - TextModelResolverService', () => { test('resolve file', async function () { const textModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8', undefined); - (accessor.textFileService.models).add(textModel.getResource(), textModel); + (accessor.textFileService.models).add(textModel.resource, textModel); await textModel.load(); - const ref = await accessor.textModelResolverService.createModelReference(textModel.getResource()); + const ref = await accessor.textModelResolverService.createModelReference(textModel.resource); const model = ref.object; const editorModel = model.textEditorModel; diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index 15488490b47..046764e60c3 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, DETECT_HC_SETTING, HC_THEME_ID, IColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IWorkbenchThemeService, IColorTheme, ITokenColorCustomizations, IFileIconTheme, ExtensionData, VS_LIGHT_THEME, VS_DARK_THEME, VS_HC_THEME, COLOR_THEME_SETTING, ICON_THEME_SETTING, CUSTOM_WORKBENCH_COLORS_SETTING, CUSTOM_EDITOR_COLORS_SETTING, DETECT_HC_SETTING, HC_THEME_ID, IColorCustomizations, CUSTOM_EDITOR_TOKENSTYLES_SETTING, IExperimentalTokenStyleCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -29,6 +29,7 @@ import * as resources from 'vs/base/common/resources'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { textmateColorsSchemaId, registerColorThemeSchemas, textmateColorSettingsSchemaId } from 'vs/workbench/services/themes/common/colorThemeSchema'; import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry'; +import { tokenStylingSchemaId } from 'vs/platform/theme/common/tokenClassificationRegistry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -92,6 +93,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { return this.configurationService.getValue(CUSTOM_EDITOR_COLORS_SETTING) || {}; } + private get tokenStylesCustomizations(): IExperimentalTokenStyleCustomizations { + return this.configurationService.getValue(CUSTOM_EDITOR_TOKENSTYLES_SETTING) || {}; + } + constructor( @IExtensionService extensionService: IExtensionService, @IStorageService private readonly storageService: IStorageService, @@ -126,6 +131,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } themeData.setCustomColors(this.colorCustomizations); themeData.setCustomTokenColors(this.tokenColorCustomizations); + themeData.setCustomTokenStyleRules(this.tokenStylesCustomizations); this.updateDynamicCSSRules(themeData); this.applyTheme(themeData, undefined, true); @@ -154,18 +160,22 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { const themeSpecificWorkbenchColors: IJSONSchema = { properties: {} }; const themeSpecificTokenColors: IJSONSchema = { properties: {} }; + const themeSpecificTokenStyling: IJSONSchema = { properties: {} }; const workbenchColors = { $ref: workbenchColorsSchemaId, additionalProperties: false }; const tokenColors = { properties: tokenColorSchema.properties, additionalProperties: false }; + const tokenStyling = { $ref: tokenStylingSchemaId, additionalProperties: false }; for (let t of event.themes) { // add theme specific color customization ("[Abyss]":{ ... }) const themeId = `[${t.settingsId}]`; themeSpecificWorkbenchColors.properties![themeId] = workbenchColors; themeSpecificTokenColors.properties![themeId] = tokenColors; + themeSpecificTokenStyling.properties![themeId] = tokenStyling; } colorCustomizationsSchema.allOf![1] = themeSpecificWorkbenchColors; tokenColorCustomizationSchema.allOf![1] = themeSpecificTokenColors; + experimentalTokenStylingCustomizationSchema.allOf![1] = themeSpecificTokenStyling; configurationRegistry.notifyConfigurationSchemaUpdated(themeSettingsConfiguration, tokenColorCustomizationConfiguration); @@ -308,6 +318,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.currentColorTheme.setCustomTokenColors(this.tokenColorCustomizations); hasColorChanges = true; } + if (e.affectsConfiguration(CUSTOM_EDITOR_TOKENSTYLES_SETTING)) { + this.currentColorTheme.setCustomTokenStyleRules(this.tokenStylesCustomizations); + hasColorChanges = true; + } if (hasColorChanges) { this.updateDynamicCSSRules(this.currentColorTheme); this.onColorThemeChange.fire(this.currentColorTheme); @@ -698,12 +712,18 @@ const tokenColorCustomizationSchema: IConfigurationPropertySchema = { default: {}, allOf: [tokenColorSchema] }; +const experimentalTokenStylingCustomizationSchema: IConfigurationPropertySchema = { + description: nls.localize('editorColorsTokenStyles', "Overrides token color and styles from the currently selected color theme."), + default: {}, + allOf: [{ $ref: tokenStylingSchemaId }] +}; const tokenColorCustomizationConfiguration: IConfigurationNode = { id: 'editor', order: 7.2, type: 'object', properties: { - [CUSTOM_EDITOR_COLORS_SETTING]: tokenColorCustomizationSchema + [CUSTOM_EDITOR_COLORS_SETTING]: tokenColorCustomizationSchema, + [CUSTOM_EDITOR_TOKENSTYLES_SETTING]: experimentalTokenStylingCustomizationSchema } }; configurationRegistry.registerConfiguration(tokenColorCustomizationConfiguration); diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index df2006b67c8..4a1b760b4e2 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -6,22 +6,26 @@ import { basename } from 'vs/base/common/path'; import * as Json from 'vs/base/common/json'; import { Color } from 'vs/base/common/color'; -import { ExtensionData, ITokenColorCustomizations, ITokenColorizationRule, IColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME, IColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { ExtensionData, ITokenColorCustomizations, ITextMateThemingRule, IColorTheme, IColorMap, IThemeExtensionPoint, VS_LIGHT_THEME, VS_HC_THEME, IColorCustomizations, IExperimentalTokenStyleCustomizations, ITokenColorizationSetting } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { convertSettings } from 'vs/workbench/services/themes/common/themeCompatibility'; import * as nls from 'vs/nls'; import * as types from 'vs/base/common/types'; import * as objects from 'vs/base/common/objects'; import * as resources from 'vs/base/common/resources'; -import { Extensions, IColorRegistry, ColorIdentifier, editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; +import { Extensions as ColorRegistryExtensions, IColorRegistry, ColorIdentifier, editorBackground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { ThemeType } from 'vs/platform/theme/common/themeService'; import { Registry } from 'vs/platform/registry/common/platform'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import { URI } from 'vs/base/common/uri'; import { parse as parsePList } from 'vs/workbench/services/themes/common/plistParser'; import { startsWith } from 'vs/base/common/strings'; +import { TokenStyle, TokenClassification, ProbeScope, TokenStylingRule, getTokenClassificationRegistry } from 'vs/platform/theme/common/tokenClassificationRegistry'; +import { MatcherWithPriority, Matcher, createMatchers } from 'vs/workbench/services/themes/common/textMateScopeMatcher'; import { IExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/common/extensionResourceLoader'; -let colorRegistry = Registry.as(Extensions.ColorContribution); +let colorRegistry = Registry.as(ColorRegistryExtensions.ColorContribution); + +let tokenClassificationRegistry = getTokenClassificationRegistry(); const tokenGroupToScopesMap = { comments: ['comment', 'punctuation.definition.comment'], @@ -33,6 +37,7 @@ const tokenGroupToScopesMap = { variables: ['variable', 'entity.name.variable'] }; + export class ColorThemeData implements IColorTheme { id: string; @@ -44,11 +49,17 @@ export class ColorThemeData implements IColorTheme { watch?: boolean; extensionData?: ExtensionData; - private themeTokenColors: ITokenColorizationRule[] = []; - private customTokenColors: ITokenColorizationRule[] = []; + private themeTokenColors: ITextMateThemingRule[] = []; + private customTokenColors: ITextMateThemingRule[] = []; private colorMap: IColorMap = {}; private customColorMap: IColorMap = {}; + private tokenStylingRules: TokenStylingRule[] | undefined = undefined; + private customTokenStylingRules: TokenStylingRule[] = []; + + private themeTokenScopeMatchers: Matcher[] | undefined; + private customTokenScopeMatchers: Matcher[] | undefined; + private constructor(id: string, label: string, settingsId: string) { this.id = id; this.label = label; @@ -56,8 +67,8 @@ export class ColorThemeData implements IColorTheme { this.isLoaded = false; } - get tokenColors(): ITokenColorizationRule[] { - const result: ITokenColorizationRule[] = []; + get tokenColors(): ITextMateThemingRule[] { + const result: ITextMateThemingRule[] = []; // the default rule (scope empty) is always the first rule. Ignore all other default rules. const foreground = this.getColor(editorForeground) || this.getDefault(editorForeground)!; @@ -71,7 +82,7 @@ export class ColorThemeData implements IColorTheme { let hasDefaultTokens = false; - function addRule(rule: ITokenColorizationRule) { + function addRule(rule: ITextMateThemingRule) { if (rule.scope && rule.settings) { if (rule.scope === 'token.info-token') { hasDefaultTokens = true; @@ -103,10 +114,57 @@ export class ColorThemeData implements IColorTheme { return color; } + public getTokenStyle(tokenClassification: TokenClassification, useDefault?: boolean): TokenStyle | undefined { + // todo: cache results + return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, this.tokenStylingRules, this.customTokenStylingRules, this); + } + public getDefault(colorId: ColorIdentifier): Color | undefined { return colorRegistry.resolveDefaultColor(colorId, this); } + public getDefaultTokenStyle(tokenClassification: TokenClassification): TokenStyle | undefined { + return tokenClassificationRegistry.resolveTokenStyle(tokenClassification, undefined, [], this); + } + + public resolveScopes(scopes: ProbeScope[]): TokenStyle | undefined { + + if (!this.themeTokenScopeMatchers) { + this.themeTokenScopeMatchers = this.themeTokenColors.map(getScopeMatcher); + } + if (!this.customTokenScopeMatchers) { + this.customTokenScopeMatchers = this.customTokenColors.map(getScopeMatcher); + } + + for (let scope of scopes) { + let foreground: string | undefined = undefined; + let fontStyle: string | undefined = undefined; + let foregroundScore = -1; + let fontStyleScore = -1; + + function findTokenStyleForScopeInScopes(scopeMatchers: Matcher[], tokenColors: ITextMateThemingRule[]) { + for (let i = 0; i < scopeMatchers.length; i++) { + const score = scopeMatchers[i](scope); + if (score >= 0) { + const settings = tokenColors[i].settings; + if (score >= foregroundScore && settings.foreground) { + foreground = settings.foreground; + } + if (score >= fontStyleScore && types.isString(settings.fontStyle)) { + fontStyle = settings.fontStyle; + } + } + } + } + findTokenStyleForScopeInScopes(this.themeTokenScopeMatchers, this.themeTokenColors); + findTokenStyleForScopeInScopes(this.customTokenScopeMatchers, this.customTokenColors); + if (foreground !== undefined || fontStyle !== undefined) { + return getTokenStyle(foreground, fontStyle); + } + } + return undefined; + } + public defines(colorId: ColorIdentifier): boolean { return this.customColorMap.hasOwnProperty(colorId) || this.colorMap.hasOwnProperty(colorId); } @@ -132,6 +190,7 @@ export class ColorThemeData implements IColorTheme { public setCustomTokenColors(customTokenColors: ITokenColorCustomizations) { this.customTokenColors = []; + this.customTokenScopeMatchers = undefined; // first add the non-theme specific settings this.addCustomTokenColors(customTokenColors); @@ -142,6 +201,16 @@ export class ColorThemeData implements IColorTheme { } } + public setCustomTokenStyleRules(tokenStylingRules: IExperimentalTokenStyleCustomizations) { + this.tokenStylingRules = []; + readCustomTokenStyleRules(tokenStylingRules, this.tokenStylingRules); + + const themeSpecificColors = tokenStylingRules[`[${this.settingsId}]`] as IExperimentalTokenStyleCustomizations; + if (types.isObject(themeSpecificColors)) { + readCustomTokenStyleRules(themeSpecificColors, this.tokenStylingRules); + } + } + private addCustomTokenColors(customTokenColors: ITokenColorCustomizations) { // Put the general customizations such as comments, strings, etc. first so that // they can be overridden by specific customizations like "string.interpolated" @@ -180,9 +249,18 @@ export class ColorThemeData implements IColorTheme { return Promise.resolve(undefined); } this.themeTokenColors = []; - this.colorMap = {}; - return _loadColorTheme(extensionResourceLoaderService, this.location, this.themeTokenColors, this.colorMap).then(_ => { + this.themeTokenScopeMatchers = undefined; + + const result = { + colors: {}, + textMateRules: [], + stylingRules: undefined + }; + return _loadColorTheme(extensionResourceLoaderService, this.location, result).then(_ => { this.isLoaded = true; + this.tokenStylingRules = result.stylingRules; + this.colorMap = result.colors; + this.themeTokenColors = result.textMateRules; }); } @@ -295,7 +373,7 @@ function toCSSSelector(extensionId: string, path: string) { return str; } -function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { +function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, result: { textMateRules: ITextMateThemingRule[], colors: IColorMap, stylingRules: TokenStylingRule[] | undefined }): Promise { if (resources.extname(themeLocation) === '.json') { return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => { let errors: Json.ParseError[] = []; @@ -307,11 +385,11 @@ function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoade } let includeCompletes: Promise = Promise.resolve(null); if (contentValue.include) { - includeCompletes = _loadColorTheme(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), resultRules, resultColors); + includeCompletes = _loadColorTheme(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), contentValue.include), result); } return includeCompletes.then(_ => { if (Array.isArray(contentValue.settings)) { - convertSettings(contentValue.settings, resultRules, resultColors); + convertSettings(contentValue.settings, result); return null; } let colors = contentValue.colors; @@ -323,38 +401,42 @@ function _loadColorTheme(extensionResourceLoaderService: IExtensionResourceLoade for (let colorId in colors) { let colorHex = colors[colorId]; if (typeof colorHex === 'string') { // ignore colors tht are null - resultColors[colorId] = Color.fromHex(colors[colorId]); + result.colors[colorId] = Color.fromHex(colors[colorId]); } } } let tokenColors = contentValue.tokenColors; if (tokenColors) { if (Array.isArray(tokenColors)) { - resultRules.push(...tokenColors); + result.textMateRules.push(...tokenColors); return null; } else if (typeof tokenColors === 'string') { - return _loadSyntaxTokens(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), tokenColors), resultRules, {}); + return _loadSyntaxTokens(extensionResourceLoaderService, resources.joinPath(resources.dirname(themeLocation), tokenColors), result); } else { return Promise.reject(new Error(nls.localize({ key: 'error.invalidformat.tokenColors', comment: ['{0} will be replaced by a path. Values in quotes should not be translated.'] }, "Problem parsing color theme file: {0}. Property 'tokenColors' should be either an array specifying colors or a path to a TextMate theme file", themeLocation.toString()))); } } + let tokenStylingRules = contentValue.tokenStylingRules; + if (tokenStylingRules && typeof tokenStylingRules === 'object') { + result.stylingRules = readCustomTokenStyleRules(tokenStylingRules, result.stylingRules); + } return null; }); }); } else { - return _loadSyntaxTokens(extensionResourceLoaderService, themeLocation, resultRules, resultColors); + return _loadSyntaxTokens(extensionResourceLoaderService, themeLocation, result); } } -function _loadSyntaxTokens(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, resultRules: ITokenColorizationRule[], resultColors: IColorMap): Promise { +function _loadSyntaxTokens(extensionResourceLoaderService: IExtensionResourceLoaderService, themeLocation: URI, result: { textMateRules: ITextMateThemingRule[], colors: IColorMap }): Promise { return extensionResourceLoaderService.readExtensionResource(themeLocation).then(content => { try { let contentValue = parsePList(content); - let settings: ITokenColorizationRule[] = contentValue.settings; + let settings: ITextMateThemingRule[] = contentValue.settings; if (!Array.isArray(settings)) { return Promise.reject(new Error(nls.localize('error.plist.invalidformat', "Problem parsing tmTheme file: {0}. 'settings' is not array."))); } - convertSettings(settings, resultRules, resultColors); + convertSettings(settings, result); return Promise.resolve(null); } catch (e) { return Promise.reject(new Error(nls.localize('error.cannotparse', "Problems parsing tmTheme file: {0}", e.message))); @@ -364,7 +446,7 @@ function _loadSyntaxTokens(extensionResourceLoaderService: IExtensionResourceLoa }); } -let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { +let defaultThemeColors: { [baseTheme: string]: ITextMateThemingRule[] } = { 'light': [ { scope: 'token.info-token', settings: { foreground: '#316bcd' } }, { scope: 'token.warn-token', settings: { foreground: '#cd9731' } }, @@ -384,3 +466,124 @@ let defaultThemeColors: { [baseTheme: string]: ITokenColorizationRule[] } = { { scope: 'token.debug-token', settings: { foreground: '#b267e6' } } ], }; + +const noMatch = (_scope: ProbeScope) => -1; + +function nameMatcher(identifers: string[], scope: ProbeScope): number { + function findInIdents(s: string, lastIndent: number): number { + for (let i = lastIndent - 1; i >= 0; i--) { + if (scopesAreMatching(s, identifers[i])) { + return i; + } + } + return -1; + } + if (scope.length < identifers.length) { + return -1; + } + let lastScopeIndex = scope.length - 1; + let lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], identifers.length); + if (lastIdentifierIndex >= 0) { + const score = (lastIdentifierIndex + 1) * 0x10000 + scope.length; + while (lastScopeIndex >= 0) { + lastIdentifierIndex = findInIdents(scope[lastScopeIndex--], lastIdentifierIndex); + if (lastIdentifierIndex === -1) { + return -1; + } + } + return score; + } + return -1; +} + + +function scopesAreMatching(thisScopeName: string, scopeName: string): boolean { + if (!thisScopeName) { + return false; + } + if (thisScopeName === scopeName) { + return true; + } + const len = scopeName.length; + return thisScopeName.length > len && thisScopeName.substr(0, len) === scopeName && thisScopeName[len] === '.'; +} + +function getScopeMatcher(rule: ITextMateThemingRule): Matcher { + const ruleScope = rule.scope; + if (!ruleScope || !rule.settings) { + return noMatch; + } + const matchers: MatcherWithPriority[] = []; + if (Array.isArray(ruleScope)) { + for (let rs of ruleScope) { + createMatchers(rs, nameMatcher, matchers); + } + } else { + createMatchers(ruleScope, nameMatcher, matchers); + } + + if (matchers.length === 0) { + return noMatch; + } + return (scope: ProbeScope) => { + let max = matchers[0].matcher(scope); + for (let i = 1; i < matchers.length; i++) { + max = Math.max(max, matchers[i].matcher(scope)); + } + return max; + }; +} + +function getTokenStyle(foreground: string | undefined, fontStyle: string | undefined): TokenStyle { + let foregroundColor = undefined; + if (foreground !== undefined) { + foregroundColor = Color.fromHex(foreground); + } + let bold, underline, italic; + if (fontStyle !== undefined) { + fontStyle = fontStyle.trim(); + if (fontStyle.length === 0) { + bold = italic = underline = false; + } else { + const expression = /-?italic|-?bold|-?underline/g; + let match; + while ((match = expression.exec(fontStyle))) { + switch (match[0]) { + case 'bold': bold = true; break; + case '-bold': bold = false; break; + case 'italic': italic = true; break; + case '-italic': italic = false; break; + case 'underline': underline = true; break; + case '-underline': underline = false; break; + } + } + } + } + return new TokenStyle(foregroundColor, bold, underline, italic); + +} + +function readCustomTokenStyleRules(tokenStylingRuleSection: IExperimentalTokenStyleCustomizations, result: TokenStylingRule[] = []) { + for (let key in tokenStylingRuleSection) { + if (key[0] !== '[') { + const classification = tokenClassificationRegistry.getTokenClassificationFromString(key); + if (classification) { + const settings = tokenStylingRuleSection[key]; + let style: TokenStyle | undefined; + if (typeof settings === 'string') { + style = getTokenStyle(settings, undefined); + } else if (isTokenColorizationSetting(settings)) { + style = getTokenStyle(settings.foreground, settings.fontStyle); + } + if (style) { + result.push(tokenClassificationRegistry.getTokenStylingRule(classification, style)); + } + } + } + } + return result; +} + +function isTokenColorizationSetting(style: any): style is ITokenColorizationSetting { + return style && (style.foreground || style.fontStyle); +} diff --git a/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts b/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts new file mode 100644 index 00000000000..4d1c66adf6f --- /dev/null +++ b/src/vs/workbench/services/themes/common/textMateScopeMatcher.ts @@ -0,0 +1,134 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +export interface MatcherWithPriority { + matcher: Matcher; + priority: -1 | 0 | 1; +} + +export interface Matcher { + (matcherInput: T): number; +} + +export function createMatchers(selector: string, matchesName: (names: string[], matcherInput: T) => number, results: MatcherWithPriority[]): void { + const tokenizer = newTokenizer(selector); + let token = tokenizer.next(); + while (token !== null) { + let priority: -1 | 0 | 1 = 0; + if (token.length === 2 && token.charAt(1) === ':') { + switch (token.charAt(0)) { + case 'R': priority = 1; break; + case 'L': priority = -1; break; + default: + console.log(`Unknown priority ${token} in scope selector`); + } + token = tokenizer.next(); + } + let matcher = parseConjunction(); + if (matcher) { + results.push({ matcher, priority }); + } + if (token !== ',') { + break; + } + token = tokenizer.next(); + } + + function parseOperand(): Matcher | null { + if (token === '-') { + token = tokenizer.next(); + const expressionToNegate = parseOperand(); + if (!expressionToNegate) { + return null; + } + return matcherInput => { + const score = expressionToNegate(matcherInput); + return score < 0 ? 0 : -1; + }; + } + if (token === '(') { + token = tokenizer.next(); + const expressionInParents = parseInnerExpression(); + if (token === ')') { + token = tokenizer.next(); + } + return expressionInParents; + } + if (isIdentifier(token)) { + const identifiers: string[] = []; + do { + identifiers.push(token); + token = tokenizer.next(); + } while (isIdentifier(token)); + return matcherInput => matchesName(identifiers, matcherInput); + } + return null; + } + function parseConjunction(): Matcher | null { + let matcher = parseOperand(); + if (!matcher) { + return null; + } + + const matchers: Matcher[] = []; + while (matcher) { + matchers.push(matcher); + matcher = parseOperand(); + } + return matcherInput => { // and + let min = matchers[0](matcherInput); + for (let i = 1; min >= 0 && i < matchers.length; i++) { + min = Math.min(min, matchers[i](matcherInput)); + } + return min; + }; + } + function parseInnerExpression(): Matcher | null { + let matcher = parseConjunction(); + if (!matcher) { + return null; + } + const matchers: Matcher[] = []; + while (matcher) { + matchers.push(matcher); + if (token === '|' || token === ',') { + do { + token = tokenizer.next(); + } while (token === '|' || token === ','); // ignore subsequent commas + } else { + break; + } + matcher = parseConjunction(); + } + return matcherInput => { // or + let max = matchers[0](matcherInput); + for (let i = 1; i < matchers.length; i++) { + max = Math.max(max, matchers[i](matcherInput)); + } + return max; + }; + } +} + +function isIdentifier(token: string | null): token is string { + return !!token && !!token.match(/[\w\.:]+/); +} + +function newTokenizer(input: string): { next: () => string | null } { + let regex = /([LR]:|[\w\.:][\w\.:\-]*|[\,\|\-\(\)])/g; + let match = regex.exec(input); + return { + next: () => { + if (!match) { + return null; + } + const res = match[0]; + match = regex.exec(input); + return res; + } + }; +} diff --git a/src/vs/workbench/services/themes/common/themeCompatibility.ts b/src/vs/workbench/services/themes/common/themeCompatibility.ts index 6518ff4a4ac..7af65c955ad 100644 --- a/src/vs/workbench/services/themes/common/themeCompatibility.ts +++ b/src/vs/workbench/services/themes/common/themeCompatibility.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ITokenColorizationRule, IColorMap } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { ITextMateThemingRule, IColorMap } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { Color } from 'vs/base/common/color'; import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; @@ -18,9 +18,9 @@ function addSettingMapping(settingId: string, colorId: string) { colorIds.push(colorId); } -export function convertSettings(oldSettings: ITokenColorizationRule[], resultRules: ITokenColorizationRule[], resultColors: IColorMap): void { +export function convertSettings(oldSettings: ITextMateThemingRule[], result: { textMateRules: ITextMateThemingRule[], colors: IColorMap }): void { for (let rule of oldSettings) { - resultRules.push(rule); + result.textMateRules.push(rule); if (!rule.scope) { let settings = rule.settings; if (!settings) { @@ -34,7 +34,7 @@ export function convertSettings(oldSettings: ITokenColorizationRule[], resultRul if (typeof colorHex === 'string') { let color = Color.fromHex(colorHex); for (let colorId of mappings) { - resultColors[colorId] = color; + result.colors[colorId] = color; } } } diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 8684b54a804..9937ca11be9 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -22,6 +22,7 @@ export const DETECT_HC_SETTING = 'window.autoDetectHighContrast'; export const ICON_THEME_SETTING = 'workbench.iconTheme'; export const CUSTOM_WORKBENCH_COLORS_SETTING = 'workbench.colorCustomizations'; export const CUSTOM_EDITOR_COLORS_SETTING = 'editor.tokenColorCustomizations'; +export const CUSTOM_EDITOR_TOKENSTYLES_SETTING = 'editor.tokenColorCustomizationsExperimental'; export interface IColorTheme extends ITheme { readonly id: string; @@ -30,7 +31,7 @@ export interface IColorTheme extends ITheme { readonly extensionData?: ExtensionData; readonly description?: string; readonly isLoaded: boolean; - readonly tokenColors: ITokenColorizationRule[]; + readonly tokenColors: ITextMateThemingRule[]; } export interface IColorMap { @@ -69,7 +70,7 @@ export interface IColorCustomizations { } export interface ITokenColorCustomizations { - [groupIdOrThemeSettingsId: string]: string | ITokenColorizationSetting | ITokenColorCustomizations | undefined | ITokenColorizationRule[]; + [groupIdOrThemeSettingsId: string]: string | ITokenColorizationSetting | ITokenColorCustomizations | undefined | ITextMateThemingRule[]; comments?: string | ITokenColorizationSetting; strings?: string | ITokenColorizationSetting; numbers?: string | ITokenColorizationSetting; @@ -77,10 +78,14 @@ export interface ITokenColorCustomizations { types?: string | ITokenColorizationSetting; functions?: string | ITokenColorizationSetting; variables?: string | ITokenColorizationSetting; - textMateRules?: ITokenColorizationRule[]; + textMateRules?: ITextMateThemingRule[]; } -export interface ITokenColorizationRule { +export interface IExperimentalTokenStyleCustomizations { + [styleRuleOrThemeSettingsId: string]: string | ITokenColorizationSetting | IExperimentalTokenStyleCustomizations | undefined; +} + +export interface ITextMateThemingRule { name?: string; scope?: string | string[]; settings: ITokenColorizationSetting; @@ -89,7 +94,7 @@ export interface ITokenColorizationRule { export interface ITokenColorizationSetting { foreground?: string; background?: string; - fontStyle?: string; // italic, underline, bold + fontStyle?: string; /* [italic|underline|bold] */ } export interface ExtensionData { @@ -106,4 +111,4 @@ export interface IThemeExtensionPoint { path: string; uiTheme?: typeof VS_LIGHT_THEME | typeof VS_DARK_THEME | typeof VS_HC_THEME; _watch: boolean; // unsupported options to watch location -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts new file mode 100644 index 00000000000..ab41c917cb8 --- /dev/null +++ b/src/vs/workbench/services/themes/test/electron-browser/tokenStyleResolving.test.ts @@ -0,0 +1,294 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ColorThemeData } from 'vs/workbench/services/themes/common/colorThemeData'; +import * as assert from 'assert'; +import { ITokenColorCustomizations } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { TokenStyle, comments, variables, types, functions, keywords, numbers, strings, getTokenClassificationRegistry } from 'vs/platform/theme/common/tokenClassificationRegistry'; +import { Color } from 'vs/base/common/color'; +import { isString } from 'vs/base/common/types'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { getPathFromAmdModule } from 'vs/base/common/amd'; +import { ExtensionResourceLoaderService } from 'vs/workbench/services/extensionResourceLoader/electron-browser/extensionResourceLoaderService'; + +let tokenClassificationRegistry = getTokenClassificationRegistry(); + +const undefinedStyle = { bold: undefined, underline: undefined, italic: undefined }; +const unsetStyle = { bold: false, underline: false, italic: false }; + +function ts(foreground: string | undefined, styleFlags: { bold?: boolean; underline?: boolean; italic?: boolean } | undefined): TokenStyle { + const foregroundColor = isString(foreground) ? Color.fromHex(foreground) : undefined; + return new TokenStyle(foregroundColor, styleFlags && styleFlags.bold, styleFlags && styleFlags.underline, styleFlags && styleFlags.italic); +} + +function tokenStyleAsString(ts: TokenStyle | undefined | null) { + if (!ts) { + return 'tokenstyle-undefined'; + } + let str = ts.foreground ? ts.foreground.toString() : 'no-foreground'; + if (ts.bold !== undefined) { + str += ts.bold ? '+B' : '-B'; + } + if (ts.underline !== undefined) { + str += ts.underline ? '+U' : '-U'; + } + if (ts.italic !== undefined) { + str += ts.italic ? '+I' : '-I'; + } + return str; +} + +function assertTokenStyle(actual: TokenStyle | undefined | null, expected: TokenStyle | undefined | null, message?: string) { + assert.equal(tokenStyleAsString(actual), tokenStyleAsString(expected), message); +} + +function assertTokenStyles(themeData: ColorThemeData, expected: { [qualifiedClassifier: string]: TokenStyle }) { + for (let qualifiedClassifier in expected) { + const classification = tokenClassificationRegistry.getTokenClassificationFromString(qualifiedClassifier); + assert.ok(classification, 'Classification not found'); + + const tokenStyle = themeData.getTokenStyle(classification!); + assertTokenStyle(tokenStyle, expected[qualifiedClassifier], qualifiedClassifier); + } +} + +suite('Themes - TokenStyleResolving', () => { + + + const fileService = new FileService(new NullLogService()); + const extensionResourceLoaderService = new ExtensionResourceLoaderService(fileService); + + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + + + test('color defaults - monokai', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-monokai/themes/monokai-color-theme.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(extensionResourceLoaderService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#88846f', undefinedStyle), + [variables]: ts('#F8F8F2', unsetStyle), + [types]: ts('#A6E22E', { underline: true }), + [functions]: ts('#A6E22E', unsetStyle), + [strings]: ts('#E6DB74', undefinedStyle), + [numbers]: ts('#AE81FF', undefinedStyle), + [keywords]: ts('#F92672', undefinedStyle) + }); + + }); + + test('color defaults - dark+', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/dark_plus.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(extensionResourceLoaderService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#6A9955', undefinedStyle), + [variables]: ts('#9CDCFE', undefinedStyle), + [types]: ts('#4EC9B0', undefinedStyle), + [functions]: ts('#DCDCAA', undefinedStyle), + [strings]: ts('#CE9178', undefinedStyle), + [numbers]: ts('#B5CEA8', undefinedStyle), + [keywords]: ts('#C586C0', undefinedStyle) + }); + + }); + + test('color defaults - light vs', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/light_vs.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(extensionResourceLoaderService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#008000', undefinedStyle), + [variables]: ts(undefined, undefinedStyle), + [types]: ts(undefined, undefinedStyle), + [functions]: ts(undefined, undefinedStyle), + [strings]: ts('#a31515', undefinedStyle), + [numbers]: ts('#09885a', undefinedStyle), + [keywords]: ts('#0000ff', undefinedStyle) + }); + + }); + + test('color defaults - hc', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-defaults/themes/hc_black.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(extensionResourceLoaderService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#7ca668', undefinedStyle), + [variables]: ts('#9CDCFE', undefinedStyle), + [types]: ts('#4EC9B0', undefinedStyle), + [functions]: ts('#DCDCAA', undefinedStyle), + [strings]: ts('#ce9178', undefinedStyle), + [numbers]: ts('#b5cea8', undefinedStyle), + [keywords]: ts('#C586C0', undefinedStyle) + }); + + }); + + test('color defaults - kimbie dark', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(extensionResourceLoaderService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#a57a4c', undefinedStyle), + [variables]: ts('#dc3958', undefinedStyle), + [types]: ts('#f06431', undefinedStyle), + [functions]: ts('#8ab1b0', undefinedStyle), + [strings]: ts('#889b4a', undefinedStyle), + [numbers]: ts('#f79a32', undefinedStyle), + [keywords]: ts('#98676a', undefinedStyle) + }); + + }); + + test('color defaults - abyss', async () => { + const themeData = ColorThemeData.createUnloadedTheme('foo'); + const themeLocation = getPathFromAmdModule(require, '../../../../../../../extensions/theme-abyss/themes/abyss-color-theme.json'); + themeData.location = URI.file(themeLocation); + await themeData.ensureLoaded(extensionResourceLoaderService); + + assert.equal(themeData.isLoaded, true); + + assertTokenStyles(themeData, { + [comments]: ts('#384887', undefinedStyle), + [variables]: ts(undefined, unsetStyle), + [types]: ts('#ffeebb', { underline: true }), + [functions]: ts('#ddbb88', unsetStyle), + [strings]: ts('#22aa44', undefinedStyle), + [numbers]: ts('#f280d0', undefinedStyle), + [keywords]: ts('#225588', undefinedStyle) + }); + + }); + + test('resolveScopes', async () => { + const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test'); + + const customTokenColors: ITokenColorCustomizations = { + textMateRules: [ + { + scope: 'variable', + settings: { + fontStyle: '', + foreground: '#F8F8F2' + } + }, + { + scope: 'keyword.operator', + settings: { + fontStyle: 'italic bold underline', + foreground: '#F92672' + } + }, + { + scope: 'storage', + settings: { + fontStyle: 'italic', + foreground: '#F92672' + } + }, + { + scope: ['storage.type', 'meta.structure.dictionary.json string.quoted.double.json'], + settings: { + foreground: '#66D9EF' + } + }, + { + scope: 'entity.name.type, entity.name.class, entity.name.namespace, entity.name.scope-resolution', + settings: { + fontStyle: 'underline', + foreground: '#A6E22E' + } + }, + ] + }; + + themeData.setCustomTokenColors(customTokenColors); + + let tokenStyle; + let defaultTokenStyle = undefined; + + tokenStyle = themeData.resolveScopes([['variable']]); + assertTokenStyle(tokenStyle, ts('#F8F8F2', unsetStyle), 'variable'); + + tokenStyle = themeData.resolveScopes([['keyword.operator']]); + assertTokenStyle(tokenStyle, ts('#F92672', { italic: true, bold: true, underline: true }), 'keyword'); + + tokenStyle = themeData.resolveScopes([['keyword']]); + assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword'); + + tokenStyle = themeData.resolveScopes([['keyword.operator']]); + assertTokenStyle(tokenStyle, ts('#F92672', { italic: true, bold: true, underline: true }), 'keyword.operator'); + + tokenStyle = themeData.resolveScopes([['keyword.operators']]); + assertTokenStyle(tokenStyle, defaultTokenStyle, 'keyword.operators'); + + tokenStyle = themeData.resolveScopes([['storage']]); + assertTokenStyle(tokenStyle, ts('#F92672', { italic: true }), 'storage'); + + tokenStyle = themeData.resolveScopes([['storage.type']]); + assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true }), 'storage.type'); + + tokenStyle = themeData.resolveScopes([['entity.name.class']]); + assertTokenStyle(tokenStyle, ts('#A6E22E', { underline: true }), 'entity.name.class'); + + tokenStyle = themeData.resolveScopes([['meta.structure.dictionary.json', 'string.quoted.double.json']]); + assertTokenStyle(tokenStyle, ts('#66D9EF', undefined), 'json property'); + + tokenStyle = themeData.resolveScopes([['keyword'], ['storage.type'], ['entity.name.class']]); + assertTokenStyle(tokenStyle, ts('#66D9EF', { italic: true }), 'storage.type'); + + }); + + test('rule matching', async () => { + const themeData = ColorThemeData.createLoadedEmptyTheme('test', 'test'); + themeData.setCustomColors({ 'editor.foreground': '#000000' }); + themeData.setCustomTokenStyleRules({ + 'types': '#ff0000', + 'classes': { foreground: '#0000ff', fontStyle: 'italic' }, + '*.static': { fontStyle: 'bold' }, + '*.declaration': { fontStyle: 'italic' }, + '*.async.static': { fontStyle: 'italic underline' }, + '*.async': { foreground: '#000fff', fontStyle: '-italic underline' } + }); + + assertTokenStyles(themeData, { + 'types': ts('#ff0000', undefinedStyle), + 'types.static': ts('#ff0000', { bold: true }), + 'types.static.declaration': ts('#ff0000', { bold: true, italic: true }), + 'classes': ts('#0000ff', { italic: true }), + 'classes.static.declaration': ts('#0000ff', { bold: true, italic: true }), + 'classes.declaration': ts('#0000ff', { italic: true }), + 'classes.declaration.async': ts('#000fff', { underline: true, italic: false }), + 'classes.declaration.async.static': ts('#000fff', { italic: true, underline: true, bold: true }), + }); + + }); +}); diff --git a/src/vs/workbench/services/workingCopy/common/workingCopyService.ts b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts new file mode 100644 index 00000000000..074a7830291 --- /dev/null +++ b/src/vs/workbench/services/workingCopy/common/workingCopyService.ts @@ -0,0 +1,161 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { Event, Emitter } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; +import { Disposable, IDisposable, toDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; +import { TernarySearchTree } from 'vs/base/common/map'; + +export const enum WorkingCopyCapabilities { + + /** + * Signals that the working copy participates + * in auto saving as configured by the user. + */ + AutoSave = 1 << 1 +} + +export interface IWorkingCopy { + + //#region Dirty Tracking + + readonly onDidChangeDirty: Event; + + isDirty(): boolean; + + //#endregion + + readonly resource: URI; + + readonly capabilities: WorkingCopyCapabilities; +} + +export const IWorkingCopyService = createDecorator('workingCopyService'); + +export interface IWorkingCopyService { + + _serviceBrand: undefined; + + //#region Dirty Tracking + + readonly onDidChangeDirty: Event; + + readonly dirtyCount: number; + + readonly hasDirty: boolean; + + isDirty(resource: URI): boolean; + + //#endregion + + + //#region Registry + + registerWorkingCopy(workingCopy: IWorkingCopy): IDisposable; + + //#endregion +} + +export class WorkingCopyService extends Disposable implements IWorkingCopyService { + + _serviceBrand: undefined; + + //#region Dirty Tracking + + private readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; + + isDirty(resource: URI): boolean { + const workingCopies = this.mapResourceToWorkingCopy.get(resource.toString()); + if (workingCopies) { + for (const workingCopy of workingCopies) { + if (workingCopy.isDirty()) { + return true; + } + } + } + + return false; + } + + get hasDirty(): boolean { + for (const workingCopy of this.workingCopies) { + if (workingCopy.isDirty()) { + return true; + } + } + + return false; + } + + get dirtyCount(): number { + let totalDirtyCount = 0; + + for (const workingCopy of this.workingCopies) { + if (workingCopy.isDirty()) { + totalDirtyCount++; + } + } + + return totalDirtyCount; + } + + //#endregion + + + //#region Registry + + private mapResourceToWorkingCopy = TernarySearchTree.forPaths>(); + private workingCopies = new Set(); + + registerWorkingCopy(workingCopy: IWorkingCopy): IDisposable { + const disposables = new DisposableStore(); + + // Registry + let workingCopiesForResource = this.mapResourceToWorkingCopy.get(workingCopy.resource.toString()); + if (!workingCopiesForResource) { + workingCopiesForResource = new Set(); + this.mapResourceToWorkingCopy.set(workingCopy.resource.toString(), workingCopiesForResource); + } + + workingCopiesForResource.add(workingCopy); + + this.workingCopies.add(workingCopy); + + // Dirty Events + disposables.add(workingCopy.onDidChangeDirty(() => this._onDidChangeDirty.fire(workingCopy))); + if (workingCopy.isDirty()) { + this._onDidChangeDirty.fire(workingCopy); + } + + return toDisposable(() => { + this.unregisterWorkingCopy(workingCopy); + dispose(disposables); + }); + } + + private unregisterWorkingCopy(workingCopy: IWorkingCopy): void { + + // Remove from registry + const workingCopiesForResource = this.mapResourceToWorkingCopy.get(workingCopy.resource.toString()); + if (workingCopiesForResource && workingCopiesForResource.delete(workingCopy) && workingCopiesForResource.size === 0) { + this.mapResourceToWorkingCopy.delete(workingCopy.resource.toString()); + } + + this.workingCopies.delete(workingCopy); + + // If copy is dirty, ensure to fire an event to signal the dirty change + // (a disposed working copy cannot account for being dirty in our model) + if (workingCopy.isDirty()) { + this._onDidChangeDirty.fire(workingCopy); + } + } + + //#endregion +} + +registerSingleton(IWorkingCopyService, WorkingCopyService, true); diff --git a/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts new file mode 100644 index 00000000000..a7797845a17 --- /dev/null +++ b/src/vs/workbench/services/workingCopy/test/common/workingCopyService.test.ts @@ -0,0 +1,145 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { URI } from 'vs/base/common/uri'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { TestWorkingCopyService } from 'vs/workbench/test/workbenchTestServices'; + +suite('WorkingCopyService', () => { + + class TestWorkingCopy extends Disposable implements IWorkingCopy { + + private readonly _onDidChangeDirty = this._register(new Emitter()); + readonly onDidChangeDirty = this._onDidChangeDirty.event; + + private readonly _onDispose = this._register(new Emitter()); + readonly onDispose = this._onDispose.event; + + readonly capabilities = 0; + + private dirty = false; + + constructor(public readonly resource: URI, isDirty = false) { + super(); + + this.dirty = isDirty; + } + + setDirty(dirty: boolean): void { + if (this.dirty !== dirty) { + this.dirty = dirty; + this._onDidChangeDirty.fire(); + } + } + + isDirty(): boolean { + return this.dirty; + } + + dispose(): void { + this._onDispose.fire(); + + super.dispose(); + } + } + + test('registry - basics', () => { + const service = new TestWorkingCopyService(); + + const onDidChangeDirty: IWorkingCopy[] = []; + service.onDidChangeDirty(copy => onDidChangeDirty.push(copy)); + + assert.equal(service.hasDirty, false); + assert.equal(service.dirtyCount, 0); + assert.equal(service.isDirty(URI.file('/')), false); + + // resource 1 + const resource1 = URI.file('/some/folder/file.txt'); + const copy1 = new TestWorkingCopy(resource1); + const unregister1 = service.registerWorkingCopy(copy1); + + assert.equal(service.dirtyCount, 0); + assert.equal(service.isDirty(resource1), false); + assert.equal(service.hasDirty, false); + + copy1.setDirty(true); + + assert.equal(service.dirtyCount, 1); + assert.equal(service.isDirty(resource1), true); + assert.equal(service.hasDirty, true); + assert.equal(onDidChangeDirty.length, 1); + assert.equal(onDidChangeDirty[0], copy1); + + copy1.setDirty(false); + + assert.equal(service.dirtyCount, 0); + assert.equal(service.isDirty(resource1), false); + assert.equal(service.hasDirty, false); + assert.equal(onDidChangeDirty.length, 2); + assert.equal(onDidChangeDirty[1], copy1); + + unregister1.dispose(); + + // resource 2 + const resource2 = URI.file('/some/folder/file-dirty.txt'); + const copy2 = new TestWorkingCopy(resource2, true); + const unregister2 = service.registerWorkingCopy(copy2); + + assert.equal(service.dirtyCount, 1); + assert.equal(service.isDirty(resource2), true); + assert.equal(service.hasDirty, true); + + assert.equal(onDidChangeDirty.length, 3); + assert.equal(onDidChangeDirty[2], copy2); + + unregister2.dispose(); + assert.equal(service.dirtyCount, 0); + assert.equal(service.hasDirty, false); + assert.equal(onDidChangeDirty.length, 4); + assert.equal(onDidChangeDirty[3], copy2); + }); + + test('registry - multiple copies on same resource', () => { + const service = new TestWorkingCopyService(); + + const onDidChangeDirty: IWorkingCopy[] = []; + service.onDidChangeDirty(copy => onDidChangeDirty.push(copy)); + + const resource = URI.parse('custom://some/folder/custom.txt'); + + const copy1 = new TestWorkingCopy(resource); + const unregister1 = service.registerWorkingCopy(copy1); + + const copy2 = new TestWorkingCopy(resource); + const unregister2 = service.registerWorkingCopy(copy2); + + copy1.setDirty(true); + + assert.equal(service.dirtyCount, 1); + assert.equal(onDidChangeDirty.length, 1); + assert.equal(service.isDirty(resource), true); + + copy2.setDirty(true); + + assert.equal(service.dirtyCount, 2); + assert.equal(onDidChangeDirty.length, 2); + assert.equal(service.isDirty(resource), true); + + unregister1.dispose(); + + assert.equal(service.dirtyCount, 1); + assert.equal(onDidChangeDirty.length, 3); + assert.equal(service.isDirty(resource), true); + + unregister2.dispose(); + + assert.equal(service.dirtyCount, 0); + assert.equal(onDidChangeDirty.length, 4); + assert.equal(service.isDirty(resource), false); + }); +}); diff --git a/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts b/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts index b963b547b00..78cb84d606e 100644 --- a/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts +++ b/src/vs/workbench/test/common/editor/untitledTextEditor.test.ts @@ -17,6 +17,7 @@ import { UntitledTextEditorInput } from 'vs/workbench/common/editor/untitledText import { timeout } from 'vs/base/common/async'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; +import { IWorkingCopyService, IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopyService'; export class TestUntitledTextEditorService extends UntitledTextEditorService { get(resource: URI) { return super.get(resource); } @@ -25,9 +26,10 @@ export class TestUntitledTextEditorService extends UntitledTextEditorService { class ServiceAccessor { constructor( - @IUntitledTextEditorService public untitledTextEditorService: TestUntitledTextEditorService, - @IModeService public modeService: ModeServiceImpl, - @IConfigurationService public testConfigurationService: TestConfigurationService) { + @IUntitledTextEditorService public readonly untitledTextEditorService: TestUntitledTextEditorService, + @IWorkingCopyService public readonly workingCopyService: IWorkingCopyService, + @IModeService public readonly modeService: ModeServiceImpl, + @IConfigurationService public readonly testConfigurationService: TestConfigurationService) { } } @@ -48,6 +50,8 @@ suite('Workbench untitled text editors', () => { test('Untitled Text Editor Service', async (done) => { const service = accessor.untitledTextEditorService; + const workingCopyService = accessor.workingCopyService; + assert.equal(service.getAll().length, 0); const input1 = service.createOrGet(); @@ -83,11 +87,17 @@ suite('Workbench untitled text editors', () => { assert.equal(service.getDirty([input2.getResource()])[0].toString(), input2.getResource().toString()); assert.equal(service.getDirty([input1.getResource()]).length, 0); + assert.ok(workingCopyService.isDirty(input2.getResource())); + assert.equal(workingCopyService.dirtyCount, 1); + service.revertAll(); assert.equal(service.getAll().length, 0); assert.ok(!input2.isDirty()); assert.ok(!model.isDirty()); + assert.ok(!workingCopyService.isDirty(input2.getResource())); + assert.equal(workingCopyService.dirtyCount, 0); + input2.dispose(); assert.ok(!service.exists(input2.getResource())); @@ -109,14 +119,17 @@ suite('Workbench untitled text editors', () => { test('Untitled no longer dirty when content gets empty', async () => { const service = accessor.untitledTextEditorService; + const workingCopyService = accessor.workingCopyService; const input = service.createOrGet(); // dirty const model = await input.resolve(); model.textEditorModel.setValue('foo bar'); assert.ok(model.isDirty()); + assert.ok(workingCopyService.isDirty(model.resource)); model.textEditorModel.setValue(''); assert.ok(!model.isDirty()); + assert.ok(!workingCopyService.isDirty(model.resource)); input.dispose(); }); @@ -138,11 +151,11 @@ suite('Workbench untitled text editors', () => { const model3 = await service.loadOrCreate({ resource: input.getResource() }); - assert.equal(model3.getResource().toString(), input.getResource().toString()); + assert.equal(model3.resource.toString(), input.getResource().toString()); const file = URI.file(join('C:\\', '/foo/file44.txt')); const model4 = await service.loadOrCreate({ resource: file }); - assert.ok(service.hasAssociatedFilePath(model4.getResource())); + assert.ok(service.hasAssociatedFilePath(model4.resource)); assert.ok(model4.isDirty()); model1.dispose(); @@ -176,11 +189,21 @@ suite('Workbench untitled text editors', () => { test('Untitled with initial content is dirty', async () => { const service = accessor.untitledTextEditorService; const input = service.createOrGet(undefined, undefined, 'Hello World'); + const workingCopyService = accessor.workingCopyService; + + let onDidChangeDirty: IWorkingCopy | undefined = undefined; + const listener = workingCopyService.onDidChangeDirty(copy => { + onDidChangeDirty = copy; + }); // dirty const model = await input.resolve(); assert.ok(model.isDirty()); + assert.equal(workingCopyService.dirtyCount, 1); + assert.equal(onDidChangeDirty, model); + input.dispose(); + listener.dispose(); }); test('Untitled created with files.defaultLanguage setting', () => { diff --git a/src/vs/workbench/test/contrib/linkProtection.test.ts b/src/vs/workbench/test/contrib/linkProtection.test.ts index 43c443119a7..72269c54214 100644 --- a/src/vs/workbench/test/contrib/linkProtection.test.ts +++ b/src/vs/workbench/test/contrib/linkProtection.test.ts @@ -70,5 +70,7 @@ suite('Link protection domain matching', () => { linkNotAllowedByRules('https://a.x.org/bar', ['https://*.x.org/foo']); linkNotAllowedByRules('https://a.b.x.org/bar', ['https://*.x.org/foo']); + + linkAllowedByRules('https://github.com', ['https://github.com/foo/bar', 'https://github.com']); }); }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts index 20bb18053ae..99d627ed559 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -112,7 +112,7 @@ suite('ExtHostLanguageFeatureCommands', function () { rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol)); ExtHostApiCommands.register(commands); - const diagnostics = new ExtHostDiagnostics(rpcProtocol); + const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService()); rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics); extHost = new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, commands, diagnostics, new NullLogService()); diff --git a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts index f319881a103..672c28dd637 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -35,7 +35,7 @@ suite('ExtHostConfiguration', function () { if (!shape) { shape = new class extends mock() { }; } - return new ExtHostConfigProvider(shape, createExtHostWorkspace(), createConfigurationData(contents)); + return new ExtHostConfigProvider(shape, createExtHostWorkspace(), createConfigurationData(contents), new NullLogService()); } function createConfigurationData(contents: any): IConfigurationInitData { @@ -283,7 +283,8 @@ suite('ExtHostConfiguration', function () { workspace: new ConfigurationModel({}, []), folders: [], configurationScopes: [] - } + }, + new NullLogService() ); let actual = testObject.getConfiguration().inspect('editor.wordWrap')!; @@ -331,7 +332,8 @@ suite('ExtHostConfiguration', function () { workspace, folders, configurationScopes: [] - } + }, + new NullLogService() ); let actual1 = testObject.getConfiguration().inspect('editor.wordWrap')!; @@ -407,7 +409,8 @@ suite('ExtHostConfiguration', function () { workspace, folders, configurationScopes: [] - } + }, + new NullLogService() ); let actual1 = testObject.getConfiguration().inspect('editor.wordWrap')!; @@ -607,7 +610,8 @@ suite('ExtHostConfiguration', function () { 'config': false, 'updatedconfig': false } - }) + }), + new NullLogService() ); const newConfigData = createConfigurationData({ diff --git a/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts b/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts index 60181c415f2..43e7087b3be 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts @@ -11,6 +11,7 @@ import { MainThreadDiagnosticsShape, IMainContext } from 'vs/workbench/api/commo import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { Emitter, Event } from 'vs/base/common/event'; +import { NullLogService } from 'vs/platform/log/common/log'; suite('ExtHostDiagnostics', () => { @@ -387,7 +388,7 @@ suite('ExtHostDiagnostics', () => { assertRegistered(): void { } - }); + }, new NullLogService()); let collection1 = diags.createDiagnosticCollection('foo'); let collection2 = diags.createDiagnosticCollection('foo'); // warns, uses a different owner @@ -436,7 +437,7 @@ suite('ExtHostDiagnostics', () => { assertRegistered(): void { } - }); + }, new NullLogService()); // diff --git a/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts b/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts index 7fbbf671196..2610d0241bb 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDocumentData.test.ts @@ -251,11 +251,7 @@ suite('ExtHostDocumentData', () => { assert.equal(range.end.character, 4); // ignore bad regular expresson /.*/ - range = data.document.getWordRangeAtPosition(new Position(0, 2), /.*/)!; - assert.equal(range.start.line, 0); - assert.equal(range.start.character, 0); - assert.equal(range.end.line, 0); - assert.equal(range.end.character, 4); + assert.throws(() => data.document.getWordRangeAtPosition(new Position(0, 2), /.*/)!); range = data.document.getWordRangeAtPosition(new Position(0, 5), /[a-z+]+/)!; assert.equal(range.start.line, 0); diff --git a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts index 68cd2940255..3793608226f 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -102,7 +102,7 @@ suite('ExtHostLanguageFeatures', function () { rpcProtocol.set(ExtHostContext.ExtHostCommands, commands); rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol)); - const diagnostics = new ExtHostDiagnostics(rpcProtocol); + const diagnostics = new ExtHostDiagnostics(rpcProtocol, new NullLogService()); rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics); extHost = new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, commands, diagnostics, new NullLogService()); diff --git a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts index bf71ebfaf5c..d90cbe04256 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -12,7 +12,7 @@ import { joinPath } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; import { MainContext, MainThreadSearchShape } from 'vs/workbench/api/common/extHost.protocol'; -import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; +import { NativeExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; import { Range } from 'vs/workbench/api/common/extHostTypes'; import { IFileMatch, IFileQuery, IPatternInfo, IRawFileMatch2, ISearchCompleteStats, ISearchQuery, ITextQuery, QueryType, resultIsMatch } from 'vs/workbench/services/search/common/search'; import { TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol'; @@ -21,9 +21,11 @@ import { NullLogService } from 'vs/platform/log/common/log'; import { URITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService'; +import { TextSearchManager } from 'vs/workbench/services/search/common/textSearchManager'; +import { NativeTextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; let rpcProtocol: TestRPCProtocol; -let extHostSearch: ExtHostSearch; +let extHostSearch: NativeExtHostSearch; const disposables = new DisposableStore(); let mockMainThreadSearch: MockMainThreadSearch; @@ -138,7 +140,7 @@ suite('ExtHostSearch', () => { rpcProtocol.set(MainContext.MainThreadSearch, mockMainThreadSearch); mockPFS = {}; - extHostSearch = new class extends ExtHostSearch { + extHostSearch = new class extends NativeExtHostSearch { constructor() { super( rpcProtocol, @@ -148,6 +150,10 @@ suite('ExtHostSearch', () => { ); this._pfs = mockPFS as any; } + + protected createTextSearchManager(query: ITextQuery, provider: vscode.TextSearchProvider): TextSearchManager { + return new NativeTextSearchManager(query, provider, this._pfs); + } }; }); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 9b4fbf6b47c..b1e238cb5d5 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -92,6 +92,8 @@ import { IBackupMainService, IWorkspaceBackupInfo } from 'vs/platform/backup/ele import { IEmptyWindowBackupInfo } from 'vs/platform/backup/node/backup'; import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; import { find } from 'vs/base/common/arrays'; +import { WorkingCopyService, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; +import { IAutoSaveConfigurationService, AutoSaveConfigurationService } from 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); @@ -206,13 +208,13 @@ export class TestTextFileService extends NativeTextFileService { @INotificationService notificationService: INotificationService, @IBackupFileService backupFileService: IBackupFileService, @IHistoryService historyService: IHistoryService, - @IContextKeyService contextKeyService: IContextKeyService, @IDialogService dialogService: IDialogService, @IFileDialogService fileDialogService: IFileDialogService, @IEditorService editorService: IEditorService, @ITextResourceConfigurationService textResourceConfigurationService: ITextResourceConfigurationService, @IElectronService electronService: IElectronService, - @IProductService productService: IProductService + @IProductService productService: IProductService, + @IAutoSaveConfigurationService autoSaveConfigurationService: IAutoSaveConfigurationService ) { super( contextService, @@ -227,13 +229,13 @@ export class TestTextFileService extends NativeTextFileService { notificationService, backupFileService, historyService, - contextKeyService, dialogService, fileDialogService, editorService, textResourceConfigurationService, electronService, - productService + productService, + autoSaveConfigurationService ); } @@ -262,6 +264,7 @@ export class TestTextFileService extends NativeTextFileService { resource: content.resource, name: content.name, mtime: content.mtime, + ctime: content.ctime, etag: content.etag, encoding: 'utf8', value: await createTextBufferFactoryFromStream(content.value), @@ -295,11 +298,13 @@ export class TestTextFileService extends NativeTextFileService { export function workbenchInstantiationService(): IInstantiationService { let instantiationService = new TestInstantiationService(new ServiceCollection([ILifecycleService, new TestLifecycleService()])); instantiationService.stub(IEnvironmentService, TestEnvironmentService); - instantiationService.stub(IContextKeyService, instantiationService.createInstance(MockContextKeyService)); + const contextKeyService = instantiationService.createInstance(MockContextKeyService); + instantiationService.stub(IContextKeyService, contextKeyService); const workspaceContextService = new TestContextService(TestWorkspace); instantiationService.stub(IWorkspaceContextService, workspaceContextService); const configService = new TestConfigurationService(); instantiationService.stub(IConfigurationService, configService); + instantiationService.stub(IAutoSaveConfigurationService, new AutoSaveConfigurationService(contextKeyService, configService)); instantiationService.stub(ITextResourceConfigurationService, new TestTextResourceConfigurationService(configService)); instantiationService.stub(IUntitledTextEditorService, instantiationService.createInstance(UntitledTextEditorService)); instantiationService.stub(IStorageService, new TestStorageService()); @@ -329,6 +334,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IEditorService, editorService); instantiationService.stub(ICodeEditorService, new TestCodeEditorService()); instantiationService.stub(IViewletService, new TestViewletService()); + instantiationService.stub(IWorkingCopyService, new TestWorkingCopyService()); return instantiationService; } @@ -974,7 +980,9 @@ export class TestFileService implements IFileService { encoding: 'utf8', mtime: Date.now(), size: 42, + isFile: true, isDirectory: false, + isSymbolicLink: false, name: resources.basename(resource) }); } @@ -996,6 +1004,7 @@ export class TestFileService implements IFileService { etag: 'index.txt', encoding: 'utf8', mtime: Date.now(), + ctime: Date.now(), name: resources.basename(resource), size: 1 }); @@ -1022,6 +1031,7 @@ export class TestFileService implements IFileService { etag: 'index.txt', encoding: 'utf8', mtime: Date.now(), + ctime: Date.now(), size: 1, name: resources.basename(resource) }); @@ -1033,8 +1043,11 @@ export class TestFileService implements IFileService { etag: 'index.txt', encoding: 'utf8', mtime: Date.now(), + ctime: Date.now(), size: 42, + isFile: true, isDirectory: false, + isSymbolicLink: false, name: resources.basename(resource) })); } @@ -1456,3 +1469,5 @@ export class TestDialogMainService implements IDialogMainService { throw new Error('Method not implemented.'); } } + +export class TestWorkingCopyService extends WorkingCopyService { } diff --git a/src/vs/workbench/workbench.common.main.ts b/src/vs/workbench/workbench.common.main.ts index 90b12c9104f..3c0ed98e54e 100644 --- a/src/vs/workbench/workbench.common.main.ts +++ b/src/vs/workbench/workbench.common.main.ts @@ -81,6 +81,9 @@ import 'vs/workbench/services/notification/common/notificationService'; import 'vs/workbench/services/extensions/common/staticExtensions'; import 'vs/workbench/services/userDataSync/common/settingsMergeService'; import 'vs/workbench/services/path/common/remotePathService'; +import 'vs/workbench/services/remote/common/remoteExplorerService'; +import 'vs/workbench/services/workingCopy/common/workingCopyService'; +import 'vs/workbench/services/autoSaveConfiguration/common/autoSaveConfigurationService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; @@ -256,4 +259,7 @@ import 'vs/workbench/contrib/userDataSync/browser/userDataSync.contribution'; // Code Actions import 'vs/workbench/contrib/codeActions/common/codeActions.contribution'; +// Test Custom Editors +import 'vs/workbench/contrib/testCustomEditors/browser/testCustomEditors'; + //#endregion diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index bed3663cfcb..0e6601077d3 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -64,7 +64,7 @@ import { NoOpTunnelService } from 'vs/platform/remote/common/tunnelService'; import { ILoggerService } from 'vs/platform/log/common/log'; import { FileLoggerService } from 'vs/platform/log/common/fileLogService'; import { IAuthTokenService } from 'vs/platform/auth/common/auth'; -import { AuthTokenService } from 'vs/platform/auth/common/authTokenService'; +import { AuthTokenService } from 'vs/workbench/services/authToken/browser/authTokenService'; import { IUserDataSyncStoreService, IUserDataSyncService, IUserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSync'; import { UserDataSyncLogService } from 'vs/platform/userDataSync/common/userDataSyncLog'; import { UserDataSyncStoreService } from 'vs/platform/userDataSync/common/userDataSyncStoreService'; diff --git a/yarn.lock b/yarn.lock index 7e7cdf4f400..3f00734e764 100644 --- a/yarn.lock +++ b/yarn.lock @@ -133,6 +133,13 @@ dependencies: "@types/node" "*" +"@types/http-proxy-agent@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/http-proxy-agent/-/http-proxy-agent-2.0.1.tgz#2f95077f6bfe7adc39cc0f0042da85997ae77fc7" + integrity sha512-dgsgbsgI3t+ZkdzF9H19uBaLsurIZJJjJsVpj4mCLp8B6YghQ7jVwyqhaL0PcVtuC3nOi0ZBhAi2Dd9jCUwdFA== + dependencies: + "@types/node" "*" + "@types/iconv-lite@0.0.1": version "0.0.1" resolved "https://registry.yarnpkg.com/@types/iconv-lite/-/iconv-lite-0.0.1.tgz#aa3b8bda2be512b1ae0a057b942e869c370a5569" @@ -197,6 +204,11 @@ "@types/uglify-js" "*" source-map "^0.6.0" +"@types/windows-foreground-love@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@types/windows-foreground-love/-/windows-foreground-love-0.3.0.tgz#26bc230b2568aa7ab7c56d35bb5653c0a6965a42" + integrity sha512-tFUVA/fiofNqOh6lZlymvQiQYPY+cZXZPR9mn9wN6/KS8uwx0zgH4Ij/jmFyRYr+x+DGZWEIeknS2BMi7FZJAQ== + "@types/winreg@^1.2.30": version "1.2.30" resolved "https://registry.yarnpkg.com/@types/winreg/-/winreg-1.2.30.tgz#91d6710e536d345b9c9b017c574cf6a8da64c518" @@ -4806,10 +4818,10 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= -jschardet@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" - integrity sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ== +jschardet@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-2.1.1.tgz#af6f8fd0b3b0f5d46a8fd9614a4fce490575c184" + integrity sha512-pA5qG9Zwm8CBpGlK/lo2GE9jPxwqRgMV7Lzc/1iaPccw6v4Rhj8Zg2BTyrdmHmxlJojnbLupLeRnaPLsq03x6Q== jsdom-no-contextify@^3.1.0: version "3.1.0" @@ -9033,10 +9045,10 @@ vscode-nsfw@1.2.8: lodash.isundefined "^3.0.1" nan "^2.10.0" -vscode-proxy-agent@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.1.tgz#7fd15e157c02176a0dca9f87840ad0991a62ca57" - integrity sha512-Nnkc7gBk9iAbbZURYZm3p/wvDvRVwDvdzEvDqF1Jh40p6przwQU/JTlV1XLrmd4cCwh6TOAWD81Z3cq+K7Xdmw== +vscode-proxy-agent@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.5.2.tgz#0c90d24d353957b841d741da7b2701e3f0a044c4" + integrity sha512-1cCNPxrWIrmUwS+1XGaXxkh3G1y7z2fpXl1sT74OZvELaryQWYb3NMxMLJJ4Q/CpPLEyuhp/bAN7nzHxxFcQ5Q== dependencies: debug "^3.1.0" http-proxy-agent "^2.1.0" @@ -9342,20 +9354,20 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.3.0.tgz#fc6843bebab1873eff0c89e31f7b74bb3c4d8947" - integrity sha512-ZvRmkNBSz2dT00w0qJ3Hd5cwYoOfkVZpHou7Xxy1kO34wQglU/8Ec4DNTvU27sS9BUzEg8kUcTTru0DxhJXrTA== +xterm-addon-search@0.4.0-beta4: + version "0.4.0-beta4" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.4.0-beta4.tgz#7762ea342c6b4f5e824d83466bd93793c9d7d779" + integrity sha512-TIbEBVhydGIxcyu/CfKJbD+BKHisMGbkAfaWlCPaWis2Xmw8yE7CKrCPn+lhZYl1MdjDVEmb8lQI6WetbC2OZA== xterm-addon-web-links@0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.2.1.tgz#6d1f2ce613e09870badf17615e7a1170a31542b2" integrity sha512-2KnHtiq0IG7hfwv3jw2/jQeH1RBk2d5CH4zvgwQe00rLofSJqSfgnJ7gwowxxpGHrpbPr6Lv4AmH/joaNw2+HQ== -xterm@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.2.0.tgz#b9980b2ae18c64ed31bcc95eace3bcecffebbbd9" - integrity sha512-oNfLqt+LmghLPOt5UcskP5Km1fXpTBHsTZ99nxJKY2N0MNFXBKIVXUcNNhHCa74JGZFMGhLT58A/UN3HcPXSfg== +xterm@4.3.0-beta17: + version "4.3.0-beta17" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.3.0-beta17.tgz#c038cc00cb5be33d2a5f083255c329d9ed186565" + integrity sha512-Lgz7vL12MBKJSgK/UXJF22Yw+uEXEE7YZDWfUD+/jbHAKN4geLQJ/Y/b3gxjLL020dnYZuayfKOr2KWdhKsmCA== y18n@^3.2.1: version "3.2.1"