Version 1.0

This commit is contained in:
Alexander R. committed 2026-07-21 22:24:25 +00:00
1 parent f3645fbfbc
commit 9edbfd3f77
4134 files changed
+1448752 -1

No files matched your search

File diff suppressed because it is too large. Load diff
+28
View File
@@ -0,0 +1,28 @@
/*!----------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Released under the MIT license
* https://github.com/microsoft/monaco-editor/blob/main/LICENSE.txt
*----------------------------------------------------------------*/
export interface IWorkerDefinition {
id: string;
entry: string;
}
export interface IFeatureDefinition {
label: string;
entry: string | string[] | undefined;
worker?: IWorkerDefinition;
}
export const features: IFeatureDefinition[];
export const languages: IFeatureDefinition[];
export type EditorLanguage = 'abap' | 'apex' | 'azcli' | 'bat' | 'bicep' | 'cameligo' | 'clojure' | 'coffee' | 'cpp' | 'csharp' | 'csp' | 'css' | 'cypher' | 'dart' | 'dockerfile' | 'ecl' | 'elixir' | 'flow9' | 'freemarker2' | 'fsharp' | 'go' | 'graphql' | 'handlebars' | 'hcl' | 'html' | 'ini' | 'java' | 'javascript' | 'json' | 'julia' | 'kotlin' | 'less' | 'lexon' | 'liquid' | 'lua' | 'm3' | 'markdown' | 'mdx' | 'mips' | 'msdax' | 'mysql' | 'objective-c' | 'pascal' | 'pascaligo' | 'perl' | 'pgsql' | 'php' | 'pla' | 'postiats' | 'powerquery' | 'powershell' | 'protobuf' | 'pug' | 'python' | 'qsharp' | 'r' | 'razor' | 'redis' | 'redshift' | 'restructuredtext' | 'ruby' | 'rust' | 'sb' | 'scala' | 'scheme' | 'scss' | 'shell' | 'solidity' | 'sophia' | 'sparql' | 'sql' | 'st' | 'swift' | 'systemverilog' | 'tcl' | 'twig' | 'typescript' | 'typespec' | 'vb' | 'wgsl' | 'xml' | 'yaml';
export type EditorFeature = 'anchorSelect' | 'bracketMatching' | 'browser' | 'caretOperations' | 'caretOperations' | 'clipboard' | 'codeAction' | 'codeEditor' | 'codelens' | 'codicon' | 'codicon' | 'colorPicker' | 'comment' | 'contextmenu' | 'cursorUndo' | 'diffEditor' | 'diffEditorBreadcrumbs' | 'dnd' | 'documentSymbols' | 'dropOrPasteInto' | 'dropOrPasteInto' | 'find' | 'floatingMenu' | 'folding' | 'fontZoom' | 'format' | 'gotoError' | 'gotoLine' | 'gotoSymbol' | 'gotoSymbol' | 'gpu' | 'hover' | 'iPadShowKeyboard' | 'inPlaceReplace' | 'indentation' | 'inlayHints' | 'inlineCompletions' | 'inlineProgress' | 'insertFinalNewLine' | 'inspectTokens' | 'internal' | 'lineSelection' | 'linesOperations' | 'linkedEditing' | 'links' | 'longLinesHelper' | 'middleScroll' | 'multicursor' | 'parameterHints' | 'placeholderText' | 'quickCommand' | 'quickHelp' | 'quickOutline' | 'readOnlyMessage' | 'referenceSearch' | 'rename' | 'sectionHeaders' | 'semanticTokens' | 'semanticTokens' | 'smartSelect' | 'snippet' | 'stickyScroll' | 'suggest' | 'suggest' | 'toggleHighContrast' | 'toggleTabFocusMode' | 'tokenization' | 'unicodeHighlighter' | 'unusualLineTerminators' | 'wordHighlighter' | 'wordOperations' | 'wordPartOperations';
export type NegatedEditorFeature = '!anchorSelect' | '!bracketMatching' | '!browser' | '!caretOperations' | '!caretOperations' | '!clipboard' | '!codeAction' | '!codeEditor' | '!codelens' | '!codicon' | '!codicon' | '!colorPicker' | '!comment' | '!contextmenu' | '!cursorUndo' | '!diffEditor' | '!diffEditorBreadcrumbs' | '!dnd' | '!documentSymbols' | '!dropOrPasteInto' | '!dropOrPasteInto' | '!find' | '!floatingMenu' | '!folding' | '!fontZoom' | '!format' | '!gotoError' | '!gotoLine' | '!gotoSymbol' | '!gotoSymbol' | '!gpu' | '!hover' | '!iPadShowKeyboard' | '!inPlaceReplace' | '!indentation' | '!inlayHints' | '!inlineCompletions' | '!inlineProgress' | '!insertFinalNewLine' | '!inspectTokens' | '!internal' | '!lineSelection' | '!linesOperations' | '!linkedEditing' | '!links' | '!longLinesHelper' | '!middleScroll' | '!multicursor' | '!parameterHints' | '!placeholderText' | '!quickCommand' | '!quickHelp' | '!quickOutline' | '!readOnlyMessage' | '!referenceSearch' | '!rename' | '!sectionHeaders' | '!semanticTokens' | '!semanticTokens' | '!smartSelect' | '!snippet' | '!stickyScroll' | '!suggest' | '!suggest' | '!toggleHighContrast' | '!toggleTabFocusMode' | '!tokenization' | '!unicodeHighlighter' | '!unusualLineTerminators' | '!wordHighlighter' | '!wordOperations' | '!wordPartOperations';
+838
View File
@@ -0,0 +1,838 @@
exports.features = [
{
"label": "anchorSelect",
"entry": [
"vs/editor/contrib/anchorSelect/browser/anchorSelect",
"vs/editor/contrib/anchorSelect/browser/anchorSelect"
]
},
{
"label": "bracketMatching",
"entry": [
"vs/editor/contrib/bracketMatching/browser/bracketMatching",
"vs/editor/contrib/bracketMatching/browser/bracketMatching"
]
},
{
"label": "browser",
"entry": [
"vs/editor/browser/coreCommands",
"vs/editor/browser/coreCommands"
]
},
{
"label": "caretOperations",
"entry": [
"vs/editor/contrib/caretOperations/browser/caretOperations",
"vs/editor/contrib/caretOperations/browser/caretOperations"
]
},
{
"label": "caretOperations",
"entry": [
"vs/editor/contrib/caretOperations/browser/transpose",
"vs/editor/contrib/caretOperations/browser/transpose"
]
},
{
"label": "clipboard",
"entry": [
"vs/editor/contrib/clipboard/browser/clipboard",
"vs/editor/contrib/clipboard/browser/clipboard"
]
},
{
"label": "codeAction",
"entry": [
"vs/editor/contrib/codeAction/browser/codeActionContributions",
"vs/editor/contrib/codeAction/browser/codeActionContributions"
]
},
{
"label": "codeEditor",
"entry": [
"vs/editor/browser/widget/codeEditor/codeEditorWidget",
"vs/editor/browser/widget/codeEditor/codeEditorWidget"
]
},
{
"label": "codelens",
"entry": [
"vs/editor/contrib/codelens/browser/codelensController",
"vs/editor/contrib/codelens/browser/codelensController"
]
},
{
"label": "codicon",
"entry": [
"vs/base/browser/ui/codicons/codicon/codicon-modifiers.css",
"vs/base/browser/ui/codicons/codicon/codicon-modifiers.css"
]
},
{
"label": "codicon",
"entry": [
"vs/base/browser/ui/codicons/codicon/codicon.css",
"vs/base/browser/ui/codicons/codicon/codicon.css"
]
},
{
"label": "colorPicker",
"entry": [
"vs/editor/contrib/colorPicker/browser/colorPickerContribution",
"vs/editor/contrib/colorPicker/browser/colorPickerContribution"
]
},
{
"label": "comment",
"entry": [
"vs/editor/contrib/comment/browser/comment",
"vs/editor/contrib/comment/browser/comment"
]
},
{
"label": "contextmenu",
"entry": [
"vs/editor/contrib/contextmenu/browser/contextmenu",
"vs/editor/contrib/contextmenu/browser/contextmenu"
]
},
{
"label": "cursorUndo",
"entry": [
"vs/editor/contrib/cursorUndo/browser/cursorUndo",
"vs/editor/contrib/cursorUndo/browser/cursorUndo"
]
},
{
"label": "diffEditor",
"entry": [
"vs/editor/browser/widget/diffEditor/diffEditor.contribution",
"vs/editor/browser/widget/diffEditor/diffEditor.contribution"
]
},
{
"label": "diffEditorBreadcrumbs",
"entry": [
"vs/editor/contrib/diffEditorBreadcrumbs/browser/contribution",
"vs/editor/contrib/diffEditorBreadcrumbs/browser/contribution"
]
},
{
"label": "dnd",
"entry": [
"vs/editor/contrib/dnd/browser/dnd",
"vs/editor/contrib/dnd/browser/dnd"
]
},
{
"label": "documentSymbols",
"entry": [
"vs/editor/contrib/documentSymbols/browser/documentSymbols",
"vs/editor/contrib/documentSymbols/browser/documentSymbols"
]
},
{
"label": "dropOrPasteInto",
"entry": [
"vs/editor/contrib/dropOrPasteInto/browser/copyPasteContribution",
"vs/editor/contrib/dropOrPasteInto/browser/copyPasteContribution"
]
},
{
"label": "dropOrPasteInto",
"entry": [
"vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorContribution",
"vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorContribution"
]
},
{
"label": "find",
"entry": [
"vs/editor/contrib/find/browser/findController",
"vs/editor/contrib/find/browser/findController"
]
},
{
"label": "floatingMenu",
"entry": [
"vs/editor/contrib/floatingMenu/browser/floatingMenu.contribution",
"vs/editor/contrib/floatingMenu/browser/floatingMenu.contribution"
]
},
{
"label": "folding",
"entry": [
"vs/editor/contrib/folding/browser/folding",
"vs/editor/contrib/folding/browser/folding"
]
},
{
"label": "fontZoom",
"entry": [
"vs/editor/contrib/fontZoom/browser/fontZoom",
"vs/editor/contrib/fontZoom/browser/fontZoom"
]
},
{
"label": "format",
"entry": [
"vs/editor/contrib/format/browser/formatActions",
"vs/editor/contrib/format/browser/formatActions"
]
},
{
"label": "gotoError",
"entry": [
"vs/editor/contrib/gotoError/browser/gotoError",
"vs/editor/contrib/gotoError/browser/gotoError"
]
},
{
"label": "gotoLine",
"entry": "vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess"
},
{
"label": "gotoSymbol",
"entry": [
"vs/editor/contrib/gotoSymbol/browser/goToCommands",
"vs/editor/contrib/gotoSymbol/browser/goToCommands"
]
},
{
"label": "gotoSymbol",
"entry": [
"vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition",
"vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition"
]
},
{
"label": "gpu",
"entry": [
"vs/editor/contrib/gpu/browser/gpuActions",
"vs/editor/contrib/gpu/browser/gpuActions"
]
},
{
"label": "hover",
"entry": [
"vs/editor/contrib/hover/browser/hoverContribution",
"vs/editor/contrib/hover/browser/hoverContribution"
]
},
{
"label": "iPadShowKeyboard",
"entry": "vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard"
},
{
"label": "inPlaceReplace",
"entry": [
"vs/editor/contrib/inPlaceReplace/browser/inPlaceReplace",
"vs/editor/contrib/inPlaceReplace/browser/inPlaceReplace"
]
},
{
"label": "indentation",
"entry": [
"vs/editor/contrib/indentation/browser/indentation",
"vs/editor/contrib/indentation/browser/indentation"
]
},
{
"label": "inlayHints",
"entry": [
"vs/editor/contrib/inlayHints/browser/inlayHintsContribution",
"vs/editor/contrib/inlayHints/browser/inlayHintsContribution"
]
},
{
"label": "inlineCompletions",
"entry": [
"vs/editor/contrib/inlineCompletions/browser/inlineCompletions.contribution",
"vs/editor/contrib/inlineCompletions/browser/inlineCompletions.contribution"
]
},
{
"label": "inlineProgress",
"entry": [
"vs/editor/contrib/inlineProgress/browser/inlineProgress",
"vs/editor/contrib/inlineProgress/browser/inlineProgress"
]
},
{
"label": "insertFinalNewLine",
"entry": [
"vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLine",
"vs/editor/contrib/insertFinalNewLine/browser/insertFinalNewLine"
]
},
{
"label": "inspectTokens",
"entry": "vs/editor/standalone/browser/inspectTokens/inspectTokens"
},
{
"label": "internal",
"entry": [
"vs/editor/internal/initialize",
"vs/editor/internal/initialize"
]
},
{
"label": "lineSelection",
"entry": [
"vs/editor/contrib/lineSelection/browser/lineSelection",
"vs/editor/contrib/lineSelection/browser/lineSelection"
]
},
{
"label": "linesOperations",
"entry": [
"vs/editor/contrib/linesOperations/browser/linesOperations",
"vs/editor/contrib/linesOperations/browser/linesOperations"
]
},
{
"label": "linkedEditing",
"entry": [
"vs/editor/contrib/linkedEditing/browser/linkedEditing",
"vs/editor/contrib/linkedEditing/browser/linkedEditing"
]
},
{
"label": "links",
"entry": [
"vs/editor/contrib/links/browser/links",
"vs/editor/contrib/links/browser/links"
]
},
{
"label": "longLinesHelper",
"entry": [
"vs/editor/contrib/longLinesHelper/browser/longLinesHelper",
"vs/editor/contrib/longLinesHelper/browser/longLinesHelper"
]
},
{
"label": "middleScroll",
"entry": [
"vs/editor/contrib/middleScroll/browser/middleScroll.contribution",
"vs/editor/contrib/middleScroll/browser/middleScroll.contribution"
]
},
{
"label": "multicursor",
"entry": [
"vs/editor/contrib/multicursor/browser/multicursor",
"vs/editor/contrib/multicursor/browser/multicursor"
]
},
{
"label": "parameterHints",
"entry": [
"vs/editor/contrib/parameterHints/browser/parameterHints",
"vs/editor/contrib/parameterHints/browser/parameterHints"
]
},
{
"label": "placeholderText",
"entry": [
"vs/editor/contrib/placeholderText/browser/placeholderText.contribution",
"vs/editor/contrib/placeholderText/browser/placeholderText.contribution"
]
},
{
"label": "quickCommand",
"entry": "vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess"
},
{
"label": "quickHelp",
"entry": "vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess"
},
{
"label": "quickOutline",
"entry": "vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess"
},
{
"label": "readOnlyMessage",
"entry": [
"vs/editor/contrib/readOnlyMessage/browser/contribution",
"vs/editor/contrib/readOnlyMessage/browser/contribution"
]
},
{
"label": "referenceSearch",
"entry": "vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch"
},
{
"label": "rename",
"entry": [
"vs/editor/contrib/rename/browser/rename",
"vs/editor/contrib/rename/browser/rename"
]
},
{
"label": "sectionHeaders",
"entry": [
"vs/editor/contrib/sectionHeaders/browser/sectionHeaders",
"vs/editor/contrib/sectionHeaders/browser/sectionHeaders"
]
},
{
"label": "semanticTokens",
"entry": [
"vs/editor/contrib/semanticTokens/browser/documentSemanticTokens",
"vs/editor/contrib/semanticTokens/browser/documentSemanticTokens"
]
},
{
"label": "semanticTokens",
"entry": [
"vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens",
"vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens"
]
},
{
"label": "smartSelect",
"entry": [
"vs/editor/contrib/smartSelect/browser/smartSelect",
"vs/editor/contrib/smartSelect/browser/smartSelect"
]
},
{
"label": "snippet",
"entry": [
"vs/editor/contrib/snippet/browser/snippetController2",
"vs/editor/contrib/snippet/browser/snippetController2"
]
},
{
"label": "stickyScroll",
"entry": [
"vs/editor/contrib/stickyScroll/browser/stickyScrollContribution",
"vs/editor/contrib/stickyScroll/browser/stickyScrollContribution"
]
},
{
"label": "suggest",
"entry": [
"vs/editor/contrib/suggest/browser/suggestController",
"vs/editor/contrib/suggest/browser/suggestController"
]
},
{
"label": "suggest",
"entry": [
"vs/editor/contrib/suggest/browser/suggestInlineCompletions",
"vs/editor/contrib/suggest/browser/suggestInlineCompletions"
]
},
{
"label": "toggleHighContrast",
"entry": "vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast"
},
{
"label": "toggleTabFocusMode",
"entry": [
"vs/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode",
"vs/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode"
]
},
{
"label": "tokenization",
"entry": [
"vs/editor/contrib/tokenization/browser/tokenization",
"vs/editor/contrib/tokenization/browser/tokenization"
]
},
{
"label": "unicodeHighlighter",
"entry": [
"vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter",
"vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter"
]
},
{
"label": "unusualLineTerminators",
"entry": [
"vs/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators",
"vs/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators"
]
},
{
"label": "wordHighlighter",
"entry": [
"vs/editor/contrib/wordHighlighter/browser/wordHighlighter",
"vs/editor/contrib/wordHighlighter/browser/wordHighlighter"
]
},
{
"label": "wordOperations",
"entry": [
"vs/editor/contrib/wordOperations/browser/wordOperations",
"vs/editor/contrib/wordOperations/browser/wordOperations"
]
},
{
"label": "wordPartOperations",
"entry": [
"vs/editor/contrib/wordPartOperations/browser/wordPartOperations",
"vs/editor/contrib/wordPartOperations/browser/wordPartOperations"
]
}
];
exports.languages = [
{
"label": "abap",
"entry": "vs/basic-languages/abap/abap.contribution"
},
{
"label": "apex",
"entry": "vs/basic-languages/apex/apex.contribution"
},
{
"label": "azcli",
"entry": "vs/basic-languages/azcli/azcli.contribution"
},
{
"label": "bat",
"entry": "vs/basic-languages/bat/bat.contribution"
},
{
"label": "bicep",
"entry": "vs/basic-languages/bicep/bicep.contribution"
},
{
"label": "cameligo",
"entry": "vs/basic-languages/cameligo/cameligo.contribution"
},
{
"label": "clojure",
"entry": "vs/basic-languages/clojure/clojure.contribution"
},
{
"label": "coffee",
"entry": "vs/basic-languages/coffee/coffee.contribution"
},
{
"label": "cpp",
"entry": "vs/basic-languages/cpp/cpp.contribution"
},
{
"label": "csharp",
"entry": "vs/basic-languages/csharp/csharp.contribution"
},
{
"label": "csp",
"entry": "vs/basic-languages/csp/csp.contribution"
},
{
"label": "css",
"entry": [
"vs/basic-languages/css/css.contribution",
"vs/language/css/monaco.contribution"
],
"worker": {
"id": "vs/language/css/cssWorker",
"entry": "vs/language/css/css.worker"
}
},
{
"label": "cypher",
"entry": "vs/basic-languages/cypher/cypher.contribution"
},
{
"label": "dart",
"entry": "vs/basic-languages/dart/dart.contribution"
},
{
"label": "dockerfile",
"entry": "vs/basic-languages/dockerfile/dockerfile.contribution"
},
{
"label": "ecl",
"entry": "vs/basic-languages/ecl/ecl.contribution"
},
{
"label": "elixir",
"entry": "vs/basic-languages/elixir/elixir.contribution"
},
{
"label": "flow9",
"entry": "vs/basic-languages/flow9/flow9.contribution"
},
{
"label": "freemarker2",
"entry": "vs/basic-languages/freemarker2/freemarker2.contribution"
},
{
"label": "fsharp",
"entry": "vs/basic-languages/fsharp/fsharp.contribution"
},
{
"label": "go",
"entry": "vs/basic-languages/go/go.contribution"
},
{
"label": "graphql",
"entry": "vs/basic-languages/graphql/graphql.contribution"
},
{
"label": "handlebars",
"entry": "vs/basic-languages/handlebars/handlebars.contribution"
},
{
"label": "hcl",
"entry": "vs/basic-languages/hcl/hcl.contribution"
},
{
"label": "html",
"entry": [
"vs/basic-languages/html/html.contribution",
"vs/language/html/monaco.contribution"
],
"worker": {
"id": "vs/language/html/htmlWorker",
"entry": "vs/language/html/html.worker"
}
},
{
"label": "ini",
"entry": "vs/basic-languages/ini/ini.contribution"
},
{
"label": "java",
"entry": "vs/basic-languages/java/java.contribution"
},
{
"label": "javascript",
"entry": "vs/basic-languages/javascript/javascript.contribution"
},
{
"label": "json",
"entry": "vs/language/json/monaco.contribution",
"worker": {
"id": "vs/language/json/jsonWorker",
"entry": "vs/language/json/json.worker"
}
},
{
"label": "julia",
"entry": "vs/basic-languages/julia/julia.contribution"
},
{
"label": "kotlin",
"entry": "vs/basic-languages/kotlin/kotlin.contribution"
},
{
"label": "less",
"entry": "vs/basic-languages/less/less.contribution"
},
{
"label": "lexon",
"entry": "vs/basic-languages/lexon/lexon.contribution"
},
{
"label": "liquid",
"entry": "vs/basic-languages/liquid/liquid.contribution"
},
{
"label": "lua",
"entry": "vs/basic-languages/lua/lua.contribution"
},
{
"label": "m3",
"entry": "vs/basic-languages/m3/m3.contribution"
},
{
"label": "markdown",
"entry": "vs/basic-languages/markdown/markdown.contribution"
},
{
"label": "mdx",
"entry": "vs/basic-languages/mdx/mdx.contribution"
},
{
"label": "mips",
"entry": "vs/basic-languages/mips/mips.contribution"
},
{
"label": "msdax",
"entry": "vs/basic-languages/msdax/msdax.contribution"
},
{
"label": "mysql",
"entry": "vs/basic-languages/mysql/mysql.contribution"
},
{
"label": "objective-c",
"entry": "vs/basic-languages/objective-c/objective-c.contribution"
},
{
"label": "pascal",
"entry": "vs/basic-languages/pascal/pascal.contribution"
},
{
"label": "pascaligo",
"entry": "vs/basic-languages/pascaligo/pascaligo.contribution"
},
{
"label": "perl",
"entry": "vs/basic-languages/perl/perl.contribution"
},
{
"label": "pgsql",
"entry": "vs/basic-languages/pgsql/pgsql.contribution"
},
{
"label": "php",
"entry": "vs/basic-languages/php/php.contribution"
},
{
"label": "pla",
"entry": "vs/basic-languages/pla/pla.contribution"
},
{
"label": "postiats",
"entry": "vs/basic-languages/postiats/postiats.contribution"
},
{
"label": "powerquery",
"entry": "vs/basic-languages/powerquery/powerquery.contribution"
},
{
"label": "powershell",
"entry": "vs/basic-languages/powershell/powershell.contribution"
},
{
"label": "protobuf",
"entry": "vs/basic-languages/protobuf/protobuf.contribution"
},
{
"label": "pug",
"entry": "vs/basic-languages/pug/pug.contribution"
},
{
"label": "python",
"entry": "vs/basic-languages/python/python.contribution"
},
{
"label": "qsharp",
"entry": "vs/basic-languages/qsharp/qsharp.contribution"
},
{
"label": "r",
"entry": "vs/basic-languages/r/r.contribution"
},
{
"label": "razor",
"entry": "vs/basic-languages/razor/razor.contribution"
},
{
"label": "redis",
"entry": "vs/basic-languages/redis/redis.contribution"
},
{
"label": "redshift",
"entry": "vs/basic-languages/redshift/redshift.contribution"
},
{
"label": "restructuredtext",
"entry": "vs/basic-languages/restructuredtext/restructuredtext.contribution"
},
{
"label": "ruby",
"entry": "vs/basic-languages/ruby/ruby.contribution"
},
{
"label": "rust",
"entry": "vs/basic-languages/rust/rust.contribution"
},
{
"label": "sb",
"entry": "vs/basic-languages/sb/sb.contribution"
},
{
"label": "scala",
"entry": "vs/basic-languages/scala/scala.contribution"
},
{
"label": "scheme",
"entry": "vs/basic-languages/scheme/scheme.contribution"
},
{
"label": "scss",
"entry": "vs/basic-languages/scss/scss.contribution"
},
{
"label": "shell",
"entry": "vs/basic-languages/shell/shell.contribution"
},
{
"label": "solidity",
"entry": "vs/basic-languages/solidity/solidity.contribution"
},
{
"label": "sophia",
"entry": "vs/basic-languages/sophia/sophia.contribution"
},
{
"label": "sparql",
"entry": "vs/basic-languages/sparql/sparql.contribution"
},
{
"label": "sql",
"entry": "vs/basic-languages/sql/sql.contribution"
},
{
"label": "st",
"entry": "vs/basic-languages/st/st.contribution"
},
{
"label": "swift",
"entry": "vs/basic-languages/swift/swift.contribution"
},
{
"label": "systemverilog",
"entry": "vs/basic-languages/systemverilog/systemverilog.contribution"
},
{
"label": "tcl",
"entry": "vs/basic-languages/tcl/tcl.contribution"
},
{
"label": "twig",
"entry": "vs/basic-languages/twig/twig.contribution"
},
{
"label": "typescript",
"entry": [
"vs/basic-languages/typescript/typescript.contribution",
"vs/language/typescript/monaco.contribution"
],
"worker": {
"id": "vs/language/typescript/tsWorker",
"entry": "vs/language/typescript/ts.worker"
}
},
{
"label": "typespec",
"entry": "vs/basic-languages/typespec/typespec.contribution"
},
{
"label": "vb",
"entry": "vs/basic-languages/vb/vb.contribution"
},
{
"label": "wgsl",
"entry": "vs/basic-languages/wgsl/wgsl.contribution"
},
{
"label": "xml",
"entry": "vs/basic-languages/xml/xml.contribution"
},
{
"label": "yaml",
"entry": "vs/basic-languages/yaml/yaml.contribution"
}
];
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","vstup","Rozlišovat malá a velká písmena","Pouze celá slova","Použit regulární výraz","vstup","Zachovávat velikost písmen","Zkontrolujte to v přístupném zobrazení pomocí {0}.","Zkontrolujte to v přístupném zobrazení pomocí příkazu Otevřít přístupné zobrazení, které se v tuto chvíli nedá aktivovat klávesovou zkratkou.","Chyba: {0}","Upozornění: {0}","Informace: {0}"," nebo {0} pro historii"," ({0} pro historii)","Zadání se vymazalo","Nesvázáno s klávesovou zkratkou","Pole výběru","Další akce...","Zadejte hledaný text","Zavřít","Zadejte hledaný text","Nenašly se žádné výsledky.","Žádné výsledky","Počet výsledků: {0}","Pro filtrování zadejte text.","Zadejte hledaný text","Filtrovat","Přibližná shoda","(prázdné)","{0}: {1}","Došlo k systémové chybě. ({0})","Došlo k neznámé chybě. Další podrobnosti naleznete v protokolu.","Došlo k neznámé chybě. Další podrobnosti naleznete v protokolu.","{0} (celkový počet chyb: {1})","Došlo k neznámé chybě. Další podrobnosti naleznete v protokolu.","Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","Možnost","Příkaz","Control","Shift","Alt","Windows","Control","Shift","Alt","Super","Rozšíření","Integrovaný terminál","Chat","Telemetrie","Aktualizovat","editor","Editor není v tuto chvíli přístupný.","{0} Pokud chcete povolit režim optimalizovaný pro čtečku obrazovky, použijte {1}","{0} Pokud chcete povolit režim optimalizovaný pro čtečku obrazovky, otevřete rychlý výběr pomocí {1} a spusťte příkaz Přepnout režim přístupnosti čtečky obrazovky, který se momentálně nedá aktivovat pomocí klávesnice.","{0} Přiřaďte klávesovou zkratku k příkazu Přepnout režim přístupnosti čtečky obrazovky tak, že pomocí {1} otevřete editor klávesových zkratek a spustíte ji.","editor","Umístit na konec i u delších řádků","Umístit na konec i u delších řádků","Odebrané sekundární kurzory","&&Zpět","Zpět","Zpět","&&Znovu","Znovu","Znovu","&&Vybrat vše","Vybrat vše","Vybrat vše","Použití vykreslování založeného na modelu DOM","Určuje, jestli jsou vložená dokončování v tuto chvíli odložená","Vyberte dobu odložení pro návrhy v řádku","Odložit vložené návrhy","Zrušit odložení vložených návrhů","Počet kurzorů byl omezen na {0}. Zvažte použití funkce [find and replace](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) pro větší změny nebo zvýšení nastavení limitu více kurzorů editoru.","Zvýšit limit více kurzorů","Přepnout sbalení nezměněných oblastí","Přepnout zobrazení přesunutých bloků kódu","Přepnout použití vloženého zobrazení, když je omezené místo","Diff Editor","Přepnout stranu","Ukončit porovnání přesunutí","Sbalit všechny nezměněné oblasti","Zobrazit všechny nezměněné oblasti","Obnovit","Prohlížeč rozdílů s podporou přístupnosti","Přejít na další rozdíl","Přejít na předchozí rozdíl","Ikona Vložit v prohlížeči rozdílů s podporou přístupnosti.","Ikona Odebrat v prohlížeči rozdílů s podporou přístupnosti.","Ikona Zavřít v prohlížeči rozdílů s podporou přístupnosti.","Zavřít","Přístupný prohlížeč rozdílů. K navigaci použijte šipku nahoru a dolů.","Nezměnily se žádné řádky.","Počet změněných řádků: 1","Počet změněných řádků: {0}","Rozdíl {0} z {1}: původní řádek {2}, {3}, změněný řádek {4}, {5}","prázdné","{0} nezměněný řádek {1}","{0} původní řádek {1} změněný řádek {2}","+ {0} změněný řádek {1}","- {0} původní řádek {1}"," pomocí {0} otevřete nápovědu k přístupnosti.","Kopírovat odstraněné řádky","Kopírovat odstraněný řádek","Kopírovat změněné řádky","Kopírovat změněný řádek","Kopírovat odstraněný řádek ({0})","Kopírovat změněný řádek ({0})","Obnovit tuto změnu","Použít vložené zobrazení, když je omezené místo","Zobrazit přesunuté bloky kódu","Obnovit blok","Obnovit výběr","Otevřít prohlížeč rozdílů s podporou přístupnosti","Sbalit nezměněnou oblast","{0} skryté čáry","Kliknutím nebo přetažením zobrazíte více nahoře.","Zobrazit nezměněnou oblast","Kliknutím nebo přetažením zobrazíte další položky níže","{0} skryté čáry","Poklikáním rozbalíte","Kód se přesunul se změnami na řádek {0}–{1}","Kód se přesunul se změnami z řádku {0}–{1}","Kód se přesunul na řádek {0}–{1}","Kód se přesunul z řádku {0}–{1}","Vrátit vybrané změny","Vrátit změnu","Barva ohraničení textu přesunutého v editoru rozdílů.","Barva aktivního ohraničení textu přesunutého v diff editoru.","Barva stínu kolem widgetů nezměněných oblastí","Dekorace řádku pro operace vložení do editoru rozdílů","Dekorace řádku pro operace odebrání do editoru rLine truncated
globalThis._VSCODE_NLS_LANGUAGE="cs";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","Eingabe","Groß-/Kleinschreibung beachten","Nur ganzes Wort suchen","Regulären Ausdruck verwenden","Eingabe","Groß-/Kleinschreibung beibehalten","Überprüfen Sie dies in der barrierefreien Ansicht mit \"{0}\".","Überprüfen Sie dies in der barrierefreien Ansicht über den Befehl \"Barrierefreie Ansicht öffnen\", der zurzeit nicht über eine Tastenzuordnung ausgelöst werden kann.","Fehler: {0}","Warnung: {0}","Info: {0}"," oder {0} für Verlauf"," ({0} für Verlauf)","Gelöschte Eingabe","Ungebunden","Auswahlfeld","Weitere Aktionen...","Zum Suchen eingeben","Schließen","Zum Suchen eingeben","Keine Ergebnisse gefunden.","Keine Ergebnisse","{0} Ergebnisse","Zum Filtern Text eingeben","Zum Suchen eingeben","Filter","Fuzzyübereinstimmung","(leer)","{0}: {1}","Ein Systemfehler ist aufgetreten ({0}).","Ein unbekannter Fehler ist aufgetreten. Weitere Details dazu finden Sie im Protokoll.","Ein unbekannter Fehler ist aufgetreten. Weitere Details dazu finden Sie im Protokoll.","{0} ({1} Fehler gesamt)","Ein unbekannter Fehler ist aufgetreten. Weitere Details dazu finden Sie im Protokoll.","STRG","UMSCHALTTASTE","ALT","Windows","STRG","UMSCHALTTASTE","ALT","Super","Steuern","UMSCHALTTASTE","Option","Befehl","Steuern","UMSCHALTTASTE","ALT","Windows","Steuern","UMSCHALTTASTE","ALT","Super","Erweiterungen","Integriertes Terminal","Chat","Telemetrie","Aktualisieren","Editor","Auf den Editor kann zurzeit nicht zugegriffen werden.","{0} Um den für die Sprachausgabe optimierten Modus zu aktivieren, verwenden Sie {1}","{0} Um den für die Sprachausgabe optimierten Modus zu aktivieren, öffnen Sie die Schnellauswahl mit {1}, und führen Sie den Befehl „Barrierefreiheitsmodus der Bildschirmsprachausgabe umschalten“ aus, der derzeit nicht über die Tastatur ausgelöst werden kann.","{0} Weisen Sie eine Tastenzuordnung für den Befehl „Barrierefreiheitsmodus der Sprachausgabe umschalten“ zu, indem Sie mit auf den Editor für Tastenzuordnungen zugreifen {1} und ihn ausführen.","Editor","Auch bei längeren Zeilen am Ende bleiben","Auch bei längeren Zeilen am Ende bleiben","Sekundäre Cursor entfernt","&&Rückgängig","Rückgängig","Rückgängig","&&Wiederholen","Wiederholen","Wiederholen","&&Alles auswählen","Alle auswählen","Alle auswählen","Verwenden des DOM-basierten Renderings","Gibt an, ob der Standbymodus von Inlinevervollständigungen derzeit aktiviert ist","Dauer für das Erinnern bei Inlinevorschlägen auswählen","Standbymodus von Inlinevorschlägen aktivieren","Aktivierung des Standbymodus von Inlinevorschlägen abbrechen","Die Anzahl der Cursor wurde auf {0} beschränkt. Erwägen Sie die Verwendung von [Suchen und Ersetzen](https://code.visualstudio.com/docs/editor/codebasics#_find-und-ersetzen) für größere Änderungen, oder erhöhen Sie die Multicursorbegrenzungseinstellung des Editors.","Erhöhen des Grenzwerts für mehrere Cursor","\"Unveränderte Bereiche reduzieren\" umschalten","\"Verschobene Codeblöcke anzeigen\" umschalten","\"Bei eingeschränktem Speicherplatz Inlineansicht verwenden\" umschalten","Diff-Editor","Seite wechseln","Vergleichsmodus beenden","Alle unveränderten Regionen reduzieren","Alle unveränderten Regionen anzeigen","Zurücksetzen","Barrierefreier Diff-Viewer","Zum nächsten Unterschied wechseln","Zum vorherigen Unterschied wechseln","Symbol für \"Einfügen\" im barrierefreien Diff-Viewer.","Symbol für \"Entfernen\" im barrierefreien Diff-Viewer.","Symbol für \"Schließen\" im barrierefreien Diff-Viewer.","Schließen","Barrierefreier Diff-Viewer. Verwenden Sie den Pfeil nach oben und unten, um zu navigieren.","keine geänderten Zeilen","1 Zeile geändert","{0} Zeilen geändert","Unterschied {0} von {1}: ursprüngliche Zeile {2}, {3}, geänderte Zeile {4}, {5}","leer","{0}: unveränderte Zeile {1}","{0} ursprüngliche Zeile {1} geänderte Zeile {2}","+ {0} geänderte Zeile(n) {1}","– {0} Originalzeile {1}"," verwenden Sie {0}, um die Hilfe zur Barrierefreiheit zu öffnen.","Gelöschte Zeilen kopieren","Gelöschte Zeile kopieren","Geänderte Zeilen kopieren","Geänderte Zeile kopieren","Gelöschte Zeile kopieren ({0})","Geänderte Zeile ({0}) kopieren","Diese Änderung rückgängig machen","Bei eingeschränktem Speicherplatz Inlineansicht verwenden","Verschobene Codeblöcke anzeigen","Block wiederherstellen","Auswahl wiederherstellen","Barrierefreien Diff-Viewer öffnen","Unveränderten Bereich falten","{0} ausgeblendete Linien","Klicken oder ziehen Sie, um oben mehr anzuzeigen.","Unveränderte Regionen anzeigen","Klicken oder ziehen Sie, um unten mehr anzuzeigen.","{0} ausgeblendete Linien","Zum Auffalten doppelklicken","Code mit Änderungen in Zeile {0}-{1} verschoben","Code mit Änderungen aus Zeile {0}-{1} verschoben","Code in Zeile {0}-{1} verschoben","Code aus Zeile {0}-{1} verschoben","Ausgewählte Änderungen zurücksetzen","Änderung zurücksetzen","Die Rahmenfarbe für Text, der im Diff-Editor verschoben wuLine truncated
globalThis._VSCODE_NLS_LANGUAGE="de";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","entrada","Coincidir mayúsculas y minúsculas","Solo palabras completas","Usar expresión regular","entrada","Conservar may/min","Inspeccione esto en la vista accesible con {0}.","Inspeccione esto en la vista accesible mediante el comando Abrir vista accesible, que actualmente no se puede desencadenar mediante el enlace de teclado.","Error: {0}","Advertencia: {0}","Información: {0}"," o {0} para el historial"," ({0} para el historial)","Entrada borrada","Sin enlazar","Seleccionar cuadro","Más Acciones...","Escriba texto para buscar","Cerrar","Escriba texto para buscar","No se encontraron resultados.","No hay resultados","{0} resultados","Escriba texto para filtrar","Escriba texto para buscar","Filtrar","Coincidencia aproximada","(vacío)","{0}: {1}","Error del sistema ({0})","Se ha producido un error desconocido. Consulte el registro para obtener más detalles.","Se ha producido un error desconocido. Consulte el registro para obtener más detalles.","{0} ({1} errores en total)","Se ha producido un error desconocido. Consulte el registro para obtener más detalles.","Ctrl","Mayús","Alt","Windows","Ctrl","Mayús","Alt","Super","Control","Mayús","Opción","Comando","Control","Mayús","Alt","Windows","Control","Mayús","Alt","Super","Extensiones","Terminal integrado","Chat","Telemetría","Actualizar","editor","No se puede acceder al editor en este momento.","{0} Para habilitar el modo optimizado para lectores de pantalla, use {1}","{0} Para habilitar el modo optimizado para lector de pantalla, abra la selección rápida con {1} y ejecute el comando Alternar modo de accesibilidad del lector de pantalla, que actualmente no se puede desencadenar mediante el teclado.","{0} Para asignar un enlace de teclado para el comando Alternar modo de accesibilidad del lector de pantalla, acceda al editor de enlaces de teclado con {1} y ejecútelo.","editor","Anclar al final incluso cuando se vayan a líneas más largas","Anclar al final incluso cuando se vayan a líneas más largas","Cursores secundarios quitados","&&Deshacer","Deshacer","Deshacer","&&Rehacer","Rehacer","Rehacer","&&Seleccionar todo","Seleccionar todo","Seleccionar todo","Uso de la representación basada en DOM","Si las finalizaciones insertadas están pospuestas actualmente","Seleccionar la duración de la pausa para las sugerencias insertadas","Posponer sugerencias insertadas","Cancelar posponer sugerencias insertadas","El número de cursores se ha limitado a {0}. Considere la posibilidad de usar [buscar y reemplazar](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) para realizar cambios mayores o aumentar la configuración del límite de varios cursores del editor.","Aumentar el límite de varios cursores","Alternar contraer regiones sin cambios","Alternar Mostrar bloques de código movidos","Alternar el uso de la vista insertada cuando el espacio es limitado","Editor de diferencias","Lado del conmutador","Salir de la comparación de movimientos","Contraer todas las regiones sin cambios","Mostrar todas las regiones sin cambios","Revertir","Visor de diferencias accesibles","Ir a la siguiente diferencia","Ir a la diferencia anterior","Icono de \"Insertar\" en el visor de diferencias accesible.","Icono de \"Quitar\" en el visor de diferencias accesible.","Icono de \"Cerrar\" en el visor de diferencias accesible.","Cerrar","Visor de diferencias accesible. Utilice la flecha hacia arriba y hacia abajo para navegar.","no se han cambiado líneas","1 línea cambiada","{0} líneas cambiadas","Diferencia {0} de {1}: línea original {2}, {3}, línea modificada {4}, {5}","vacío","{0} línea sin cambios {1}","{0} línea original {1} línea modificada {2}","+ {0} línea modificada {1}","- {0} línea original {1}"," use {0} para abrir la ayuda de accesibilidad.","Copiar líneas eliminadas","Copiar línea eliminada","Copiar líneas cambiadas","Copiar línea cambiada","Copiar la línea eliminada ({0})","Copiar línea cambiada ({0})","Revertir este cambio","Uso de la vista insertada cuando el espacio es limitado","Mostrar bloques de código movidos","Revertir bloque","Revertir selección","Abrir visor de diferencias accesibles","Plegar la región sin cambios","{0} líneas ocultas","Haga clic o arrastre para mostrar más arriba","Mostrar región sin cambios","Hacer clic o arrastrar para mostrar más abajo","{0} líneas ocultas","Doble clic para desplegar","Código movido con cambios en la línea {0}-{1}","Código movido con cambios de la línea {0}-{1}","Código movido a la línea {0}-{1}","Código movido de la línea {0}-{1}","Revertir los cambios seleccionados","Revertir el cambio","Color del borde del texto que se movió en el editor de diferencias.","Color del borde de texto activo que se movió en el editor de diferencias.","Color de la sombra paralela en torno a los widgets de región sin cambios.","Decoración de línea para las inserciones en el editor de diferencias.","Decoración de línea paLine truncated
globalThis._VSCODE_NLS_LANGUAGE="es";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","entrée","Respecter la casse","Mot entier","Utiliser une expression régulière","entrée","Préserver la casse","Inspectez ceci dans l’affichage accessible avec {0}.","Inspectez ceci dans l’affichage accessible via la commande Open Accessible View qui ne peut pas être déclenchée via une combinaison de touches pour l’instant.","Erreur : {0}","Avertissement : {0}","Info : {0}"," ou {0} pour l'histoire"," ({0} pour l'histoire)","Entrée effacée","Indépendant","Zone de sélection","Plus d'actions...","Entrer le texte à rechercher","Fermer","Entrer le texte à rechercher","Aucun résultat trouvé.","Aucun résultat","{0} résultats","Type à filtrer","Entrer le texte à rechercher","Filtrer","Correspondance approximative","(vide)","{0}: {1}","Une erreur système s'est produite ({0})","Une erreur inconnue s’est produite. Veuillez consulter le journal pour plus de détails.","Une erreur inconnue s’est produite. Veuillez consulter le journal pour plus de détails.","{0} ({1} erreurs au total)","Une erreur inconnue s’est produite. Veuillez consulter le journal pour plus de détails.","Ctrl","Maj","Alt","Windows","Ctrl","Maj","Alt","Super","Contrôle","Maj","Option","Commande","Contrôle","Maj","Alt","Windows","Contrôle","Maj","Alt","Super","Extensions","Terminal intégré","Conversation","Télémétrie","Mettre à jour","éditeur","L’éditeur n’est pas accessible pour le moment.","{0} Pour activer le mode optimisé du lecteur d’écran, utilisez {1}","{0} Pour activer le mode optimisé du lecteur d’écran, ouvrez la sélection rapide avec {1} et exécutez la commande Activer/Désactiver le mode d’accessibilité du lecteur d’écran, qui n’est pas déclenchable via le clavier pour le moment.","{0} Attribuez une combinaison de touches à la commande Activer/Désactiver le mode d’accessibilité du lecteur d’écran en accédant à l’éditeur de combinaisons de touches avec {1} et exécutez-la.","éditeur","Aligner par rapport à la fin même en cas de passage à des lignes plus longues","Aligner par rapport à la fin même en cas de passage à des lignes plus longues","Curseurs secondaires supprimés","Ann&&uler","Annuler","Annuler","&&Rétablir","Rétablir","Rétablir","&&Sélectionner tout","Tout sélectionner","Tout sélectionner","Utiliser le rendu basé sur DOM","Indique si les complétions en ligne sont actuellement répétées","Sélectionnez la durée de mise en veille pour les suggestions en ligne","Répétition des suggestions inline","Annuler la répétition des suggestions inline","Le nombre de curseurs a été limité à {0}. Envisagez d’utiliser [rechercher et remplacer](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) pour les modifications plus importantes ou augmentez la limite du nombre de curseurs multiples du paramètre.","Augmenter la limite de curseurs multiples","Activer/désactiver réduire les régions inchangées","Activer/désactiver l’affichage des blocs de code déplacés","Activer/désactiver Utiliser la vue inline lorsque l'espace est limité","Éditeur de différences","Changer de côté","Quitter Comparer le déplacement","Réduire toutes les régions inchangées","Afficher toutes les régions inchangées","Restaurer","Visionneuse Diff accessible","Accéder à la différence suivante","Accéder la différence précédente","Icône « Insérer » dans la visionneuse diff accessible.","Icône « Supprimer » dans la visionneuse diff accessible.","Icône de « Fermer » dans la visionneuse diff accessible.","Fermer","Visionneuse diff accessible. Utilisez les flèches haut et bas pour naviguer.","aucune ligne changée","1 ligne changée","{0} lignes changées","Différence {0} sur {1} : ligne d'origine {2}, {3}, ligne modifiée {4}, {5}","vide","{0} ligne inchangée {1}","{0} ligne d'origine {1} ligne modifiée {2}","+ {0} ligne modifiée {1}","- {0} ligne d'origine {1}"," utilisez {0} pour ouvrir l’aide sur l’accessibilité.","Copier les lignes supprimées","Copier la ligne supprimée","Copier les lignes modifiées","Copier la ligne modifiée","Copier la ligne supprimée ({0})","Copier la ligne modifiée ({0})","Annuler la modification","Utiliser la vue inline lorsque l'espace est limité","Afficher les blocs de code déplacés","Rétablir le bloc","Rétablir la sélection","Ouvrir la visionneuse diff accessible","Replier la région inchangée","{0} lignes masquées","Cliquez ou faites glisser pour afficher plus d'éléments au-dessus","Afficher la région inchangée","Cliquez ou faites glisser pour afficher plus d'éléments en dessous","{0} lignes masquées","Double-cliquer pour déplier","Code déplacé avec des modifications vers la ligne {0}-{1}","Code déplacé avec des modifications à partir de la ligne {0}-{1}","Code déplacé vers la ligne {0}-{1}","Code déplacé à partir de la ligne {0}-{1}","Rétablir les modifications sélectionnées","Rétablir la Line truncated
globalThis._VSCODE_NLS_LANGUAGE="fr";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","input","Maiuscole/minuscole","Parola intera","Usa espressione regolare","input","Mantieni maiuscole/minuscole","Ispezionarlo nella visualizzazione accessibile con {0}.","Ispezionarlo nella visualizzazione accessibile tramite il comando Apri visualizzazione accessibile che attualmente non è attivabile tramite il tasto di scelta rapida.","Errore: {0}","Avviso: {0}","Info: {0}"," o {0} per la cronologia"," ({0} per la cronologia)","Input cancellato","Non associato","Casella di selezione","Altre azioni...","Digitare per la ricerca","Chiudi","Digitare per la ricerca","Non sono stati trovati risultati.","Nessun risultato","{0} risultati","Digitare per filtrare","Digitare per la ricerca","Filtro","Corrispondenza fuzzy","(vuoto)","{0}: {1}","Si è verificato un errore di sistema ({0})","Si è verificato un errore sconosciuto. Per altri dettagli, vedere il log.","Si è verificato un errore sconosciuto. Per altri dettagli, vedere il log.","{0} ({1} errori in totale)","Si è verificato un errore sconosciuto. Per altri dettagli, vedere il log.","CTRL","MAIUSC","ALT","Windows","CTRL","MAIUSC","ALT","Super","CTRL","MAIUSC","Opzione","Comando","CTRL","MAIUSC","ALT","Windows","CTRL","MAIUSC","ALT","Super","Estensioni","Terminale integrato","Chat","Telemetria","Aggiorna","editor","L'editor non è accessibile in questo momento.","{0} Per abilitare la modalità ottimizzata per l'utilità per la lettura dello schermo usare {1}","{0} Per abilitare la modalità ottimizzata per l'utilità per la lettura dello schermo, aprire la selezione rapida con {1} ed eseguire il comando Attiva/Disattiva modalità di accessibilità dell'utilità per la lettura dello schermo, attualmente non attivabile tramite tastiera.","{0} Assegnare un tasto di scelta rapida per il comando Attiva/Disattiva modalità di accessibilità dell'utilità per la lettura dello schermo accedendo all'editor dei tasti di scelta rapida con {1} ed eseguirlo.","editor","Si attiene alla fine anche quando si passa a righe più lunghe","Si attiene alla fine anche quando si passa a righe più lunghe","Cursori secondari rimossi","&&Annulla","Annulla azione","Annulla azione","&&Ripeti","Ripeti","Ripeti","&&Seleziona tutto","Seleziona tutto","Seleziona tutto","Usa rendering basato su DOM","Indica se i completamenti inline sono rinviati","Selezionare la durata della sospensione per i suggerimenti inline","Rinvia suggerimenti inline","Annulla il rinvio dei suggerimenti inline","Il numero di cursori è stato limitato a {0}. Provare a usare [Trova e sostituisci](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) per modifiche di dimensioni maggiori o aumentare l'impostazione del limite di più cursori dell'editor.","Aumentare limite multi-cursore","Attiva/Disattiva comprimi aree non modificate","Attiva/Disattiva mostra blocchi di codice spostati","Attiva/disattiva la visualizzazione inline quando lo spazio è limitato","Editor diff","Interruttore laterale","Esci da Sposta confronto","Comprimi tutte le aree non modificate","Mostra tutte le aree non modificate","Ripristina","Visualizzatore differenze accessibile","Vai alla differenza successiva","Vai alla differenza precedente","Icona per \"Inserisci\" nel visualizzatore differenze accessibile.","Icona per \"Rimuovi\" nel visualizzatore differenze accessibile.","Icona per \"Chiudi\" nel visualizzatore differenze accessibile.","Chiudi","Visualizzatore differenze accessibile. Usare le frecce SU e GIÙ per spostarsi.","nessuna riga modificata","1 riga modificata","{0} righe modificate","Differenza {0} di {1}: riga originale {2}, {3}, riga modificata {4}, {5}","vuota","{0} riga non modificata {1}","{0} riga originale {1} riga modificata {2}","+ {0} riga modificata {1}","- {0} riga originale {1}"," utilizzare {0} per aprire la Guida all'accessibilità.","Copia le righe eliminate","Copia la riga eliminata","Copia righe modificate","Copia riga modificata","Copia la riga eliminata ({0})","Copia riga modificata ({0})","Ripristina questa modifica","Usa la visualizzazione inline quando lo spazio è limitato","Mostra blocchi di codice spostati","Ripristina blocco","Ripristina selezione","Apri Visualizzatore differenze accessibile","Ridurre area non modificata","{0} righe nascoste","Fai clic o trascina per visualizzare altri elementi sopra","Mostra area non modificata","Fai clic o trascina per visualizzare altri elementi sotto","{0} righe nascoste","Fare doppio clic per espandere","Codice spostato con modifiche alla riga {0}-{1}","Codice spostato con modifiche dalla riga {0}-{1}","Codice spostato alla riga {0}-{1}","Codice spostato dalla riga {0}-{1}","Ripristina modifiche selezionate","Annulla modifica","Colore del bordo per il testo spostato nell'editor diff.","Colore del bordo attivo per il testo spostato nell'editor diff.","Colore dell'ombreggiatura intorno ai widget dell'area non modificata.","Effetto di riga per gli inserimenti nell'editor diff.","Effetto di riga per le rimLine truncated
globalThis._VSCODE_NLS_LANGUAGE="it";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","入力","大文字と小文字を区別する","単語単位で検索する","正規表現を使用する","入力","保持する","{0} を使用して、ユーザー補助対応のビューでこれを検査します。","キー バインドを介して現在トリガーできない [ユーザー補助対応のビューを開く] コマンドを使用して、ユーザー補助対応のビューでこれを検査します。","エラー: {0}","警告: {0}","情報: {0}"," または履歴の {0}"," (履歴の {0})","クリアされた入力","バインドなし","ボックスを選択","その他の操作...","入力して検索","閉じる","入力して検索","結果が見つかりません。","結果はありません","{0} 件の結果","入力してフィルター","入力して検索","フィルター","あいまい一致","(空)","{0}: {1}","システム エラーが発生しました ({0})","不明なエラーが発生しました。ログで詳細を確認してください。","不明なエラーが発生しました。ログで詳細を確認してください。","{0} (合計 {1} エラー)","不明なエラーが発生しました。ログで詳細を確認してください。","Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","オプション","コマンド","Control","Shift","Alt","Windows","Control","Shift","Alt","Super","拡張機能","統合ターミナル","チャット","テレメトリ","更新","エディター","この時点では、エディターにアクセスできません。","{0} スクリーン リーダー最適化モードを有効にするには、{1} を使用します","{0} スクリーン リーダー最適化モードを有効にするには、{1} でクイック ピックを開き、[スクリーン リーダー アクセシビリティ モードの切り替え] コマンドを実行します。これは現在キーボードからトリガーできません。","{0} {1} でキーバインド エディターにアクセスし、スクリーン リーダー アクセシビリティ モードの切り替えコマンドにキーバインドを割り当てて実行してください。","エディター","長い行に移動しても行末に位置します","長い行に移動しても行末に位置します","セカンダリ カーソルが削除されました","元に戻す(&&U)","元に戻す","元に戻す","やり直し(&&R)","やり直し","やり直し","すべて選択(&&S)","すべてを選択","すべてを選択","DOM ベースのレンダリングを使用する","インライン補完が現在一時停止されているかどうか","インライン候補のスヌーズ期間を選択してください","インライン提案の再通知","インライン提案の再通知をキャンセル","カーソルの数は {0} に制限されています。大きな変更を行う場合は、[検索と置換](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) を使用することを検討してください。","マルチ カーソルの上限を増やす","変更されていない領域の折りたたみの切り替え","移動したコード ブロックの表示の切り替え","スペースが制限されている場合に [インライン ビューの使用] を切り替える","差分エディター","サイドの切り替え","比較移動の終了","変更されていないすべてのリージョンを折りたたむ","変更されていないすべてのリージョンを表示する","元に戻す","アクセシビリティの高い差分ビューアー","次の差分に移動","前の差分に移動","アクセシビリティの高い差分ビューアーの [挿入] のアイコン。","アクセシビリティの高い差分ビューアーの [削除] のアイコン。","アクセシビリティの高い差分ビューアーの [閉じる] のアイコン。","閉じる","アクセス可能な Diff Viewer。上下方向キーを使用して移動します。","変更された行はありません","1 行が変更されました","{0} 行が変更されました","相違 {0}/{1}: 元の行 {2}、{3}。変更された行 {4}、{5}","空白","{0} 変更されていない行 {1}","{0} 元の行 {1} 変更された行 {2}","+ {0} 変更された行 {1}","- {0} 元の行 {1}"," {0}を使用して、アクセシビリティのヘルプを開きます。","削除された行のコピー","削除された行のコピー","変更された行のコピー","変更された行のコピー","削除された行のコピー ({0})","変更された行のコピー ({0})","この変更を元に戻す","スペースが制限されている場合はインライン ビューを使用する","移動されたコード ブロックの表示","ブロックを元に戻す","選択範囲を元に戻す","アクセシビリティの高い差分ビューアーを開く","変更されLine truncated
globalThis._VSCODE_NLS_LANGUAGE="ja";
+4
View File
@@ -0,0 +1,4 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","input","Match Case","Match Whole Word","Use Regular Expression","input","Preserve Case","Inspect this in the accessible view with {0}.","Inspect this in the accessible view via the command Open Accessible View which is currently not triggerable via keybinding.","Error: {0}","Warning: {0}","Info: {0}"," or {0} for history"," ({0} for history)","Cleared Input","Unbound","Select Box","More Actions...","Type to search","Close","Type to search","No results found.","No results","{0} results","Type to filter","Type to search","Filter","Fuzzy Match","(empty)","{0}: {1}","A system error occurred ({0})","An unknown error occurred. Please consult the log for more details.","An unknown error occurred. Please consult the log for more details.","{0} ({1} errors in total)","An unknown error occurred. Please consult the log for more details.","Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","Option","Command","Control","Shift","Alt","Windows","Control","Shift","Alt","Super","Extensions","Integrated Terminal","Chat","Telemetry","Update","editor","The editor is not accessible at this time.","{0} To enable screen reader optimized mode, use {1}","{0} To enable screen reader optimized mode, open the quick pick with {1} and run the command Toggle Screen Reader Accessibility Mode, which is currently not triggerable via keyboard.","{0} Please assign a keybinding for the command Toggle Screen Reader Accessibility Mode by accessing the keybindings editor with {1} and run it.","editor","Stick to the end even when going to longer lines","Stick to the end even when going to longer lines","Removed secondary cursors","&&Undo","Undo","Undo","&&Redo","Redo","Redo","&&Select All","Select All","Select All","Use DOM-based rendering","Whether inline completions are currently snoozed","Select snooze duration for Inline Suggestions","Snooze Inline Suggestions","Cancel Snooze Inline Suggestions","The number of cursors has been limited to {0}. Consider using [find and replace](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) for larger changes or increase the editor multi cursor limit setting.","Increase Multi Cursor Limit","Toggle Collapse Unchanged Regions","Toggle Show Moved Code Blocks","Toggle Use Inline View When Space Is Limited","Diff Editor","Switch Side","Exit Compare Move","Collapse All Unchanged Regions","Show All Unchanged Regions","Revert","Accessible Diff Viewer","Go to Next Difference","Go to Previous Difference","Icon for 'Insert' in accessible diff viewer.","Icon for 'Remove' in accessible diff viewer.","Icon for 'Close' in accessible diff viewer.","Close","Accessible Diff Viewer. Use arrow up and down to navigate.","no lines changed","1 line changed","{0} lines changed","Difference {0} of {1}: original line {2}, {3}, modified line {4}, {5}","blank","{0} unchanged line {1}","{0} original line {1} modified line {2}","+ {0} modified line {1}","- {0} original line {1}"," use {0} to open the accessibility help.","Copy deleted lines","Copy deleted line","Copy changed lines","Copy changed line","Copy deleted line ({0})","Copy changed line ({0})","Revert this change","Use Inline View When Space Is Limited","Show Moved Code Blocks","Revert Block","Revert Selection","Open Accessible Diff Viewer","Fold Unchanged Region","{0} hidden lines","Click or drag to show more above","Show Unchanged Region","Click or drag to show more below","{0} hidden lines","Double click to unfold","Code moved with changes to line {0}-{1}","Code moved with changes from line {0}-{1}","Code moved to line {0}-{1}","Code moved from line {0}-{1}","Revert Selected Changes","Revert Change","The border color for text that got moved in the diff editor.","The active border color for text that got moved in the diff editor.","The color of the shadow around unchanged region widgets.","Line decoration for inserts in the diff editor.","Line decoration for removals in the diff editor.","The background color of the diff editor's header","The background color of the multi file diff editor","The border color of the multi file diff editor","Loading...","No Changed Files","Editor","The number of spaces a tab is equal to. This setting is overridden based on the file contents when {0} is on.","The number of spaces used for indentation or `\"tabSize\"` to use the value from `#editor.tabSize#`. This setting is overridden based on the file contents when `#editor.detectIndentation#` is on.","Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when {0} is on.","Controls whether {0} and {1} will be automatically detected when a file is opened based on the file contents.","Remove trailing auto inserted whitespace.","Special handling for large files to disable certain memory intensive features.","Turn off Word Based Suggestions.","Only suggest words from the active document.","Suggest words from all open documents of the same language.","Suggest words from all Line truncated
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0}({1})","입력","대/소문자 구분","단어 단위로","정규식 사용","입력","대/소문자 보존","{0}을(를) 사용하여 접근성 보기에서 이를 검사합니다.","현재 키 바인딩을 통해 트리거할 수 없는 접근성 보기 열기 명령을 통해 접근성 보기에서 이를 검사합니다.","오류: {0}","경고: {0}","정보: {0}"," 또는 {0} 기록의 경우"," ({0} 기록용)","입력이 지워짐","바인딩 안 됨","Box 선택","기타 작업...","입력하여 검색","닫기","입력하여 검색","결과를 찾을 수 없습니다.","결과 없음","{0}개 결과","필터링할 형식","입력하여 검색","필터","유사 항목 일치","(비어 있음)","{0}: {1}","시스템 오류가 발생했습니다({0}).","알 수 없는 오류가 발생했습니다. 자세한 내용은 로그를 참조하세요.","알 수 없는 오류가 발생했습니다. 자세한 내용은 로그를 참조하세요.","{0}(총 {1}개의 오류)","알 수 없는 오류가 발생했습니다. 자세한 내용은 로그를 참조하세요.","Ctrl","Shift","<Alt>","Windows","Ctrl","Shift","<Alt>","슈퍼","Ctrl","Shift","옵션","명령","Ctrl","Shift","<Alt>","Windows","Ctrl","Shift","<Alt>","슈퍼","확장","통합 터미널","채팅","원격 분석","업데이트","편집기","현재 편집기에 액세스할 수 없습니다.","{0} 화면 읽기 프로그램 최적화 모드를 사용하도록 설정하려면 {1}을(를) 사용합니다.","{0} 화면 읽기 프로그램 최적화 모드를 사용하도록 설정하려면 {1}을(를) 사용하여 빠른 선택을 열고 화면 읽기 프로그램 접근성 모드 토글 명령을 실행합니다(이 명령은 현재 키보드를 통해 트리거할 수 없음).","{0} {1}을(를) 사용하여 키 바인딩 편집기에 액세스하여 화면 읽기 프로그램 접근성 모드 토글 명령에 대한 키 바인딩을 할당하고 실행하세요.","편집기","더 긴 줄로 이동하는 경우에도 끝에 고정","더 긴 줄로 이동하는 경우에도 끝에 고정","보조 커서가 제거됨","실행 취소(&&U)","실행 취소","실행 취소","다시 실행(&&R)","다시 실행","다시 실행","모두 선택(&&S)","모두 선택","모두 선택","DOM 기반 렌더링 사용","인라인 완성이 현재 다시 알림 상태인지 여부","인라인 제안의 다시 알림 기간 선택","인라인 제안 다시 알림","인라인 제안 다시 알림 취소","커서 수를 {0}개로 제한했습니다. 더 큰 변경 내용을 위해서는 [찾아서 교체](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace)를 사용하거나 편집기 다중 커서 제한 설정을 늘리는 것이 좋습니다.","다중 커서 제한 늘리기","변경되지 않은 영역 축소 토글","이동된 코드 블록 표시 토글","공간이 제한된 경우 인라인 보기 사용 설정/해제","diff 편집기","스위치 쪽","비교 이동 종료","변경되지 않은 모든 영역 축소","변경되지 않은 모든 영역 표시","되돌리기","액세스 가능한 Diff 뷰어","다음 다른 항목으로 이동","다음 다른 항목으로 이동","액세스 가능한 Diff 뷰어의 '삽입' 아이콘.","액세스 가능한 Diff 뷰어의 '제거' 아이콘.","접근 가능한 Diff 뷰어의 '닫기' 아이콘.","닫기","액세스 가능한 Diff 뷰어입니다. 탐색하려면 위쪽 및 아래쪽 화살표를 사용합니다.","변경된 줄 없음","선 1개 변경됨","줄 {0}개 변경됨","차이 {0}/{1}: 원래 줄 {2}, {3}, 수정된 줄 {4}, {5}","비어 있음","{0} 변경되지 않은 줄 {1}","{0} 원래 줄 {1} 수정된 줄 {2}","+ {0} 수정된 줄 {1}","- {0} 원래 줄 {1}"," {0}을(를) 사용하여 접근성 도움말을 엽니다.","삭제된 줄 복사","삭제된 줄 복사","변경된 줄 복사","변경된 줄 복사","삭제된 줄 복사({0})","변경된 줄({0}) 복사","이 변경 내용 되돌리기","공간이 제한된 경우 인라인 보기 사용","이동된 코드 블록 표시","블록 되돌리기","선택 항목 되돌리기","액세스 가능한 Diff 뷰어 열기","변경되지 않은 영역 접기","숨겨진 선 {0}개","위에 자세히 표시하려면 클릭하거나 끌어다 놓기","변경되지 않은 영역 표시","아래에 자세히 표시하려면 클릭하거나 끌어다 놓기","숨겨진 선 {0}개","두 번 클릭하여 펼치기","변경 사항과 함께 코드가 {0} - {1}줄로 이동됨","변경 사항과 함께 코드가 {0} - {1}줄에서 이동됨","코드가 {0} - {1}줄로 이동됨","코드가 {0} - {1}줄에서 이동됨","선택한 변경 내용 되돌리기","변경 내용 되돌리기","diff 편집기에서 이동된 텍스트의 테두리 색입니다.","diff 편집기에서 이동된 텍스트의 활성 테두리 색입니다.","변경되지 않은 영역 위젯 주위의 그림자 색입니다.","diff Line truncated
globalThis._VSCODE_NLS_LANGUAGE="ko";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","wejście","Uwzględnij wielkość liter","Uwzględnij całe wyrazy","Użyj wyrażenia regularnego","wejście","Zachowaj wielkość liter","Dokonaj inspekcji w widoku z ułatwieniami dostępu za pomocą {0}","Dokonaj inspekcji w widoku z ułatwieniami dostępu za pomocą polecenia Otwórz widok z ułatwieniami dostępu, którego obecnie nie można wyzwalać za pośrednictwem powiązania klawiszy.","Błąd: {0}","Ostrzeżenie: {0}","Informacje: {0}"," lub {0}, aby wyświetlić historię"," ({0} — wyświetlenie historii)","Wyczyszczone dane wejściowe","Niepowiązany","Pole opcji","Więcej akcji...","Wpisz, aby wyszukać","Zamknij","Wpisz, aby wyszukać","Nie znaleziono żadnych wyników.","Brak wyników","Wyniki: {0}","Wpisz, aby filtrować","Wpisz, aby wyszukać","Filtr","Dopasowanie rozmyte","(puste)","{0}: {1}","Wystąpił błąd systemu ({0})","Wystąpił nieznany błąd. Sprawdź dziennik, aby uzyskać więcej szczegółów.","Wystąpił nieznany błąd. Sprawdź dziennik, aby uzyskać więcej szczegółów.","{0} (łączna liczba błędów: {1})","Wystąpił nieznany błąd. Sprawdź dziennik, aby uzyskać więcej szczegółów.","Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","Opcja","Polecenie","Control","Shift","Alt","Windows","Control","Shift","Alt","Super","Rozszerzenia","Zintegrowany terminal","Czat","Telemetria","Aktualizuj","edytor","Edytor nie jest w tej chwili dostępny.","{0} Aby włączyć tryb zoptymalizowany czytnika zawartości ekranu, użyj {1}","{0} Aby włączyć tryb zoptymalizowany czytnika zawartości ekranu, otwórz szybkie wybieranie za pomocą {1} i uruchom polecenie Przełącz tryb ułatwień dostępu czytnika zawartości ekranu, którego obecnie nie można wyzwalać za pomocą klawiatury.","{0} Przypisz powiązanie klawiszy dla polecenia Przełącz tryb ułatwień dostępu czytnika zawartości ekranu, uzyskując dostęp do edytora powiązań klawiszy za pomocą {1} i uruchom go.","edytor","Trzymaj się końca nawet podczas przechodzenia do dłuższych wierszy","Trzymaj się końca nawet podczas przechodzenia do dłuższych wierszy","Usunięto pomocnicze kursory","&&Cofnij","Cofnij","Cofnij","&&Ponów","Ponów","Ponów","&&Wybierz wszystko","Wybierz wszystko","Wybierz wszystko","Użyj renderowania opartego na modelu DOM","Określa, czy uzupełnienia wbudowane są obecnie odłożone","Wybierz czas trwania odkładania dla sugestii śródwierszowych","Odłóż wbudowane sugestie","Anuluj odkładanie wbudowanych sugestii","Liczba kursorów została ograniczona do {0}. Rozważ użycie funkcji [wyszukaj i zamień](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) w celu wprowadzenia większych zmian lub zwiększenia ustawienia limitu wielu kursorów edytora.","Zwiększ limit wielu kursorów","Przełącz Zwiń niezmienione regiony","Przełącz pokazywanie przeniesionych bloków kodu","Przełącz użycie widoku wbudowanego, gdy spacja jest ograniczona","Edytor różnic","Przełącz stronę","Zakończ porównywanie przenoszenia","Zwiń wszystkie niezmienione regiony","Pokaż wszystkie niezmienione regiony","Przywróć","Podgląd różnic z ułatwieniami dostępu","Przejdź do następnej różnicy","Przejdź do poprzedniej różnicy","Ikona „Wstaw” w przeglądarce różnic z ułatwieniami dostępu.","Ikona „Usuń” w przeglądarce różnic z ułatwieniami dostępu.","Ikona „Zamknij” w przeglądarce różnic z ułatwieniami dostępu.","Zamknij","Podgląd różnic dotyczących ułatwień dostępu. Użyj strzałki w górę i w dół, aby nawigować.","brak zmienionych wierszy","1 wiersz zmieniony","zmienione wiersze: {0}","Różnica {0} z {1}: oryginalny wiersz {2}, {3}, zmodyfikowany wiersz {4}, {5}","puste","{0} niezmieniony wiersz {1}","{0} oryginalny wiersz {1} zmodyfikowany wiersz {2}","+ {0} zmodyfikowany wiersz {1}","— {0} oryginalny wiersz {1}"," użyj {0} do otwierania pomocy dotyczącej ułatwień dostępu.","Kopiuj usunięte wiersze","Kopiuj usunięty wiersz","Kopiuj zmienione wiersze","Kopiuj zmieniony wiersz","Kopiuj usunięty wiersz ({0})","Kopiuj zmieniony wiersz ({0})","Odwróć tę zmianę","Użyj widoku wbudowanego, gdy spacja jest ograniczona","Pokaż przeniesione bloki kodu","Przywróć blok","Przywróć zaznaczenie","Otwórz podgląd różnic z ułatwieniami dostępu","Zwiń obszar bez zmian","Liczba ukrytych wierszy: {0}","Kliknij lub przeciągnij, aby pokazać więcej powyżej","Pokaż niezmieniony region","Kliknij lub przeciągnij, aby pokazać więcej pniżej","Liczba ukrytych wierszy: {0}","Kliknij dwukrotnie, aby rozwinąć","Kod został przeniesiony ze zmianami do wiersza {0}-{1}","Kod został przeniesiony ze zmianami z wiersza {0}-{1}","Kod został przeniesiony do wiersza {0}-{1}","Kod przeniesiony z wiersza {0}-{1}","Przywróć wybrane zmiany","Cofnij zmianę","Kolor obramowania tekstu, który został przeniesiony w edytorze różnic.","Aktywny kolorLine truncated
globalThis._VSCODE_NLS_LANGUAGE="pl";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,nLine truncated
globalThis._VSCODE_NLS_LANGUAGE="pt-br";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","входные данные","С учетом регистра","Слово целиком","Использовать регулярное выражение","входные данные","Сохранить регистр","Проверьте этот аспект в доступном представлении с помощью {0}.","Проверьте этот аспект в представлении с поддержкой специальных возможностей с помощью команды \"Открыть представление с поддержкой специальных возможностей\", которую в настоящее время нельзя активировать с помощью настраиваемого сочетания клавиш.","Ошибка: {0}","Предупреждение: {0}","Информация: {0}"," или {0} для журнала"," ({0} для журнала)","Очищенные входные данные","свободный","Поле выбора","Дополнительные действия...","Ввод для поиска","Закрыть","Ввод для поиска","Результаты не найдены.","Нет результатов","Результатов: {0}","Введите текст для фильтра","Ввод для поиска","Фильтр","Нечеткое совпадение","(пусто)","{0}: {1}","Произошла системная ошибка ({0})","Произошла неизвестная ошибка. Подробные сведения см. в журнале.","Произошла неизвестная ошибка. Подробные сведения см. в журнале.","{0} (всего ошибок: {1})","Произошла неизвестная ошибка. Подробные сведения см. в журнале.","CTRL","SHIFT","ALT","Windows","CTRL","SHIFT","ALT","Super","CTRL","SHIFT","Параметр","Команда","CTRL","SHIFT","ALT","Windows","CTRL","SHIFT","ALT","Super","Расширения","Встроенный терминал","Чат","Телеметрия","Обновить","редактор","Сейчас редактор недоступен.","{0} Чтобы включить оптимизированный режим читателя, используйте {1}","{0} Чтобы включить оптимизированный режим читателя, откройте быстрый выбор с помощью {1} и выполните команду \"Активация режима специальных возможностей для читателя\", который сейчас не может быть активирован с помощью клавиатуры.","{0} Назначьте сочетание клавиш для команды \"Активация режима специальных возможностей для читателя\", используя редактор настраиваемых сочетаний клавиш с помощью {1} и запустите его.","редактор","Размещать на конце даже для более длинных строк","Размещать на конце даже для более длинных строк","Дополнительные курсоры удалены.","&&Отменить","Отменить","Отменить","&&Повторить","Вернуть","Вернуть","&&Выделить все","Выбрать все","Выбрать все","Использование отрисовки на основе DOM","Отложены ли в настоящее время встроенные завершения","Выберите длительность откладывания для встроенных предложений","Отложить встроенные предложения","Отменить откладывание встроенных предложений","Число курсоров ограничено {0}. Для проведения крупных изменений рекомендуется использовать [поиск и замену](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) или увеличить значение параметра ограничения нескольких курсоров в редакторе.","Увеличить значение ограничения нескольких курсоров","Переключатель свертывания неизмененных регионов","Показать или скрыть перемещенные блоки кода","Переключатель \"Использовать встроенное представление при ограниченном пространстве\"","Редактор несовпадений","ПереключитLine truncated
globalThis._VSCODE_NLS_LANGUAGE="ru";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","giriş","Büyük/Küçük Harf Eşleştir","Sözcüğün Tamamını Eşleştir","Normal İfade Kullan","giriş","Büyük/Küçük Harfi Koru","Bunu {0} ile erişilebilir görünümde inceleyin.","Şu anda tuş bağlama ile tetiklenemeyen Erişilebilir Görünümü Aç komutu aracılığıyla bu öğeyi erişilebilir görünümde inceleyin.","Hata: {0}","Uyarı: {0}","Bilgi: {0}"," veya geçmiş için {0}"," (geçmiş için {0})","Temizlenen Giriş","Sınırsız","Kutu Seç","Diğer Eylemler...","Aramak için yazın","Kapat","Aramak için yazın","Hiçbir sonuç bulunamadı.","Sonuç yok","{0} sonuç","Filtrelemek için yazın","Aramak için yazın","Filtre","Benzer Öğe Eşleşmesi","(boş)","{0}: {1}","Sistem hatası oluştu ({0})","Beklenmeyen bir hata oluştu. Daha fazla ayrıntı için lütfen günlüğe bakın.","Beklenmeyen bir hata oluştu. Daha fazla ayrıntı için lütfen günlüğe bakın.","{0} (toplam {1} hata)","Beklenmeyen bir hata oluştu. Daha fazla ayrıntı için lütfen günlüğe bakın.","Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","Seçenek","Command","Control","Shift","Alt","Windows","Control","Shift","Alt","Super","Uzantılar","Tümleşik Terminal","Sohbet","Telemetri","Güncelleştir","düzenleyici","Düzenleyiciye şu anda erişilemiyor.","{0} Ekran okuyucu için iyileştirilmiş modu etkinleştirmek için şunu kullanın{1}","{0} Ekran okuyucu için iyileştirilmiş modu etkinleştirmek için {1} ile hızlı seçimi açın ve şu anda klavye aracılığıyla tetiklenemeyen Ekran Okuyucusu Erişilebilirlik Modunu Aç/Kapat komutunu çalıştırın.","{0} Lütfen tuş bağlamaları düzenleyicisine erişerek Ekran Okuyucusu Erişilebilirlik Modunu Aç/Kapat komutu için bir tuş bağlaması atayın {1} ve çalıştırın.","düzenleyici","Daha uzun satırlara giderken bile sonda kal","Daha uzun satırlara giderken bile sonda kal","İkincil imleçler kaldırıldı","&&Geri Al","Geri Al","Geri Al","&&Yinele","Yinele","Yinele","&&Tümünü Seç","Tümünü Seç","Tümünü Seç","DOM tabanlı işleme kullan","Satır içi tamamlamaların şu anda ertelenip ertelenmediği","Satır İçi Öneriler için erteleme süresini seçin","Satır İçi Önerileri Ertele","Satır İçi Önerileri Ertelemeyi İptal Et","İmleç sayısı {0} ile sınırlandırıldı. Daha büyük değişiklikler için [bul ve değiştir](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) kullanmayı veya düzenleyici çoklu imleç sınırı ayarını artırmayı düşünün.","Çoklu İmleç Sınırını Artırma","Değişmeyen Bölgeleri Daraltmayı Aç/Kapat","Taşınan Kod Bloklarını Göster/Gizle","Alan Sınırlı Olduğunda Satır İçi Görünümü Kullan'a Geç","Fark Düzenleyicisi","Diğer Yüze Geç","Taşımayı Karşılaştır'dan Çık","Değiştirilmemiş Tüm Bölgeleri Daralt","Değiştirilmemiş Tüm Bölgeleri Göster","Geri Dön","Erişilebilir Fark Görüntüleyicisi","Sonraki Farka Git","Önceki Farka Git","Erişilebilir fark görüntüleyicisinde 'Ekle' simgesi.","Erişilebilir fark görüntüleyicisinde 'Kaldır' simgesi.","Erişilebilir fark görüntüleyicisinde 'Kapat' simgesi.","Kapat","Erişilebilir Fark Görüntüleyicisi. Gezinmek için yukarı ve aşağı ok tuşlarını kullanın.","satır değiştirilmedi","1 satır değiştirildi","{0} satır değiştirildi","{0} / {1} fark: özgün satır: {2}, {3}, değiştirilen satır: {4}, {5}","boş","{0} değiştirilmemiş satır {1}","{0} özgün satır: {1} değiştirilen satır: {2}","+ {0} değiştirilmiş satır {1}","- {0} özgün satır {1}"," erişilebilirlik yardımını açmak için {0} kullanın.","Silinen satırları kopyala","Silinen satırı kopyala","Değiştirilen satırları kopyala","Değiştirilen satırı kopyala","Silinen satırı kopyala ({0})","Değiştirilen satırı kopyala ({0})","Bu değişikliği geri al","Alan Sınırlı Olduğunda Satır İçi Görünümü Kullan","Taşınan Kod Bloklarını Göster","Bloğu Geri Döndür","Seçimi Geri Döndür","Erişilebilir Fark Görüntüleyicisi'ni aç","Değişmeyen Bölgeyi Katlayın","{0} gizli satır","Yukarıda daha fazlasını göstermek için tıklayın veya sürükleyin","Değişmeyen Bölgeyi Göster","Aşağıda daha fazlasını göstermek için tıklayın veya sürükleyin","{0} gizli satır","Katlamayı kaldırmak için çift tıkla","Kod, değişikliklerle {0}-{1} satırına taşındı","Kod, değişikliklerle {0}-{1} satırından taşındı","Kod, {0}-{1} satırına taşındı","Kod, {0}-{1} satırından taşındı","Seçili Değişiklikleri Ger Döndür","Değişikliği Geri Döndür","Fark düzenleyicisinde taşınan metnin kenarlık rengi.","Fark düzenleyicisinde taşınan metnin aktif kenarlık rengi.","Değiştirilmemiş bölge pencere öğelerinin etrafındaki gölgenin rengi.","Fark düzenleyicisindeki eklemeler için satır dekorasyonu.","Fark düzeLine truncated
globalThis._VSCODE_NLS_LANGUAGE="tr";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","输入","区分大小写","全字匹配","使用正则表达式","输入","保留大小写","在辅助视图中用 {0} 检查此项。","通过命令“打开辅助视图”在辅助视图中检查此项,该命令当前无法通过键绑定触发。","错误: {0}","警告: {0}","信息: {0}"," 或使用 {0} 以查看历史记录"," (使用 {0} 查看历史记录)","清除的输入","未绑定","选择框","更多操作...","要搜索的类型","关闭","要搜索的类型","未找到任何结果。","无结果","{0} 个结果","要筛选的类型","要搜索的类型","筛选器","模糊匹配","(空)","{0}: {1}","发生了系统错误 ({0})","出现未知错误。有关详细信息,请参阅日志。","出现未知错误。有关详细信息,请参阅日志。","{0} 个(共 {1} 个错误)","出现未知错误。有关详细信息,请参阅日志。","Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","Option","Command","Control","Shift","Alt","Windows","Control","Shift","Alt","Super","扩展","集成终端","聊天","遥测","更新","编辑器","现在无法访问编辑器。","{0} 若要启用屏幕阅读器优化模式,请使用 {1}","{0} 若要启用屏幕阅读器优化模式,请使用 {1} 打开快速选取,然后运行“切换屏幕阅读器辅助功能模式”命令;当前无法通过键盘触发此命令。","{0} 请通过使用 {1} 访问键绑定编辑器并运行它,为“切换屏幕阅读器辅助功能模式”命令分配键绑定。","编辑器","即使转到较长的行,也一直到末尾","即使转到较长的行,也一直到末尾","已删除辅助游标","撤消(&&U)","撤消","撤消","恢复(&&R)","恢复","恢复","全选(&&S)","选择全部","选择全部","使用基于 DOM 的呈现","当前是否推迟内联补全","选择内联建议的推迟时长","推迟内联建议","取消推迟内联建议","已将光标数限制为 {0}。请考虑使用 [查找和替换](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace)进行较大的更改或增加编辑器多光标限制设置。","增加多光标限制","切换折叠未更改的区域","切换显示移动的代码块","在空间受限时切换使用内联视图","差异编辑器","切换侧面","退出比较移动","折叠所有未更改的区域","显示所有未更改的区域","还原","可访问的差异查看器","转至下一个差异","转至上一个差异","可访问差异查看器中“插入”的图标。","可访问差异查看器中“删除”的图标。","可访问差异查看器中“关闭”的图标。","关闭","可访问的差异查看器。使用向上和向下箭头导航。","未更改行","更改了 1 行","更改了 {0} 行","差异 {0}/ {1}: 原始行 {2},{3},修改后的行 {4},{5}","空白","{0} 未更改的行 {1}","{0}原始行{1}修改的行{2}","+ {0}修改的行{1}","- {0}原始行{1}"," 使用 {0} 打开辅助功能帮助。","复制已删除的行","复制已删除的行","复制更改的行","复制更改的行","复制已删除的行({0})","复制更改的行({0})","还原此更改","空间受限时使用内联视图","显示移动的代码块","还原块","还原所选内容","打开可访问差异查看器","折叠未更改的区域","{0} 个隐藏的行","单击或拖动可在上面显示更多内容","显示未更改的区域","单击或拖动可在下方显示更多内容","{0} 个隐藏的行","双击展开","代码已移动至行 {0}-{1},有更改","代码已从行 {0}-{1} 移动,有更改","代码已移动到行 {0} {1}","代码已从行 {0}-{1} 移动","还原所选更改","还原更改","在差异编辑器中移动的文本的边框颜色。","在差异编辑器中移动的文本的活动边框颜色。","未更改区域小组件周围的阴影颜色。","差异编辑器中插入项的线条修饰。","差异编辑器中删除项的线条修饰。","差异编辑器标题的背景色","多文件差异编辑器的背景色","多文件差异编辑器的边框颜色","正在加载...","没有已更改的文件","编辑器","一个制表符等于的空格数。当 {0} 打开时,将根据文件内容替代此设置。","用于缩进或 `\"tabSize\"` 的空格数,可使用 `#editor.tabSize#` 中的值。当 `#editor.detectIndentation#` 处于打开状态时,将根据文件内容替代此设置。","按 `Tab` 时插入空格。当 {0} 打开时,将根据文件内容替代此设置。","控制在基于文件内容打开文件时是否自动检测 {0} 和 {1}。","删除自动插入的尾随空白符号。","对大型文件进行特殊处理,禁用某些内存密集型功能。","关闭基于字词的建议。","仅建议活动文档中的字词。","建议使用同一语言的所有打开的文档中的字词。","建议所有打开的文档中的字词。","控制是否应根据文档中的字词计算补全,以及从哪些文档中计算补全。","对Line truncated
globalThis._VSCODE_NLS_LANGUAGE="zh-cn";
+9
View File
@@ -0,0 +1,9 @@
/*!-----------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Version: 0.55.1(516f350bdaf7a82f6731bd128a9ec86a6e5fa47d)
* Released under the MIT license
* https://github.com/microsoft/vscode/blob/main/LICENSE.txt
*-----------------------------------------------------------*/
globalThis._VSCODE_NLS_MESSAGES=["{0} ({1})","輸入","大小寫須相符","全字拼寫須相符","使用規則運算式","輸入","保留大小寫","使用 {0} 在可存取檢視中檢查此項目。","透過目前無法透過按鍵繫結關係觸發的開啟可存取檢視命令,在可存取檢視中檢查此項目。","錯誤: {0}","警告: {0}","資訊: {0}"," 或 {0} 以取得歷程記錄"," ({0} 以取得歷程記錄)","已清除輸入","未繫結","選取方塊","更多操作","要搜尋的類型","關閉","要搜尋的類型","找不到結果。","沒有結果","{0} 個結果","要篩選的類型","要搜尋的類型","篩選","模糊比對","(空的)","{0}: {1}","發生系統錯誤 ({0})","發生未知的錯誤。如需詳細資訊,請參閱記錄檔。","發生未知的錯誤。如需詳細資訊,請參閱記錄檔。","{0} (總計 {1} 個錯誤)","發生未知的錯誤。如需詳細資訊,請參閱記錄檔。","Ctrl","Shift","Alt","Windows","Ctrl","Shift","Alt","Super","Control","Shift","Option","Command","Control","Shift","Alt","Windows","Control","Shift","Alt","Super","延伸模組","整合式終端","聊天","遙測","更新","編輯器","目前無法存取此編輯器。","{0} 若要啟用螢幕助讀程式最佳化模式,請使用 {1}","{0} 若要啟用螢幕助讀程式最佳化模式,,請使用 {1} 開啟快速挑選,然後執行 [切換螢幕助讀程式協助工具模式] 命令,該模式目前無法透過鍵盤觸發。","{0} 請使用 {1} 存取按鍵繫結關係編輯器並加以執行,以為 [切換螢幕助讀程式協助工具模式] 命令指派按鍵繫結關係。","編輯器","即使行的長度過長,仍要堅持至結尾","即使行的長度過長,仍要堅持至結尾","已移除次要資料指標","復原(&&U)","復原","復原","取消復原(&&R)","重做","重做","全選(&&S)","全選","全選","使用 DOM 型轉譯","目前內嵌完成是否已被延遲","選取內嵌建議的延遲持續時間","延遲內嵌建議","取消延遲的內嵌建議","游標數目已限制為 {0}。請考慮使用 [尋找和取代](https://code.visualstudio.com/docs/editor/codebasics#_find-and-replace) 進行較大型的變更,或增加編輯器的多重游標限制設定。","增加多重游標限制","切換摺疊未變更的區域","切換顯示移動的程式碼區塊","當空間有限時切換使用內嵌檢視","Diff 編輯器","切換側邊","結束比較移動","摺疊所有未變更的區域","顯示所有未變更的區域","還原","可存取的 Diff 檢視器","移至下一個差異","移至上一個差異","易存取差異檢視器中的 [插入] 圖示。","易存取差異檢視器中的 [移除] 圖示。","易存取差異檢視器中的 [關閉] 圖示。","關閉","可存取的 Diff 檢視器。使用向上和向下箭頭來瀏覽。","未變更任一行","已變更 1 行","已變更 {0} 行","{1} 項差異中的第 {0} 項: 原始行 {2}、{3},修改行 {4}、{5}","空白","{0} 未變更行 {1}","{0} 原始行 {1} 修改的行 {2}","+ {0} 修改行 {1}","- {0} 原始行 {1}"," 使用 {0} 以開啟協助工具說明。","複製已刪除的行","複製已刪除的行","複製變更的行","複製變更的行","複製已刪除的行 ({0})","複製變更的行 ({0})","還原此變更","空間有限時使用內嵌檢視","顯示移動的程式碼區塊","還原區塊","還原選取範圍","開啟易存取差異檢視器","摺疊未變更的區域","{0} 條隱藏行","按一下或拖曳以在上方顯示更多內容","顯示未變更的區域","按一下或拖曳以在下方顯示更多內容","{0} 條隱藏行","按兩下以展開","行 {0}-{1} 的程式碼已移動,且有所變更","行 {0}-{1} 的程式碼已移動,且有所變更","程式碼已移至行 {0}-{1}","行 {0}-{1} 的程式碼已移動","還原選取的變更","還原變更","在 Diff 編輯器中移動的文字的框線色彩。","在 Diff 編輯器中移動的文字的作用中框線色彩。","未變更的區域小工具周圍的陰影色彩。","Diff 編輯器中用於插入的線條裝飾。","Diff 編輯器中用於移除的線條裝飾。","Diff 編輯器標頭的背景色彩","多重檔案 Diff 編輯器的背景色彩","多重檔案 Diff 編輯器的框線色彩","正在載入...","沒有變更的檔案","編輯器","與 Tab 相等的空格數量。當 {0} 已開啟時,會根據檔案內容覆寫此設定。","用於縮排或 'tabSize' 使用 `\"editor.tabSize\"` 值的空格數目。當 '#editor.detectIndentation#' 開啟時,會根據檔案內容覆寫這個設定。","在按 `Tab` 時插入空格。當 {0} 開啟時,會根據檔案內容覆寫此設定。","根據檔案內容,控制當檔案開啟時,是否自動偵測 {0} 和 {1}。","移除尾端自動插入的空白字元。","針對大型檔案停用部分高記憶體需求功能的特殊處理方式。","關閉 Word 型建議。","僅建議來自使用中文件中的字組。","建議來自所有已Line truncated
globalThis._VSCODE_NLS_LANGUAGE="zh-tw";
+57
View File
@@ -0,0 +1,57 @@
import { mainWindow } from './window.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class WindowManager {
constructor() {
// --- Zoom Factor
this.mapWindowIdToZoomFactor = new Map();
}
static { this.INSTANCE = new WindowManager(); }
getZoomFactor(targetWindow) {
return this.mapWindowIdToZoomFactor.get(this.getWindowId(targetWindow)) ?? 1;
}
getWindowId(targetWindow) {
return targetWindow.vscodeWindowId;
}
}
function addMatchMediaChangeListener(targetWindow, query, callback) {
if (typeof query === 'string') {
query = targetWindow.matchMedia(query);
}
query.addEventListener('change', callback);
}
/** The zoom scale for an index, e.g. 1, 1.2, 1.4 */
function getZoomFactor(targetWindow) {
return WindowManager.INSTANCE.getZoomFactor(targetWindow);
}
const userAgent = navigator.userAgent;
const isFirefox = (userAgent.indexOf('Firefox') >= 0);
const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0);
const isChrome = (userAgent.indexOf('Chrome') >= 0);
const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0));
const isWebkitWebView = (!isChrome && !isSafari && isWebKit);
(userAgent.indexOf('Electron/') >= 0);
const isAndroid = (userAgent.indexOf('Android') >= 0);
let standalone = false;
if (typeof mainWindow.matchMedia === 'function') {
const standaloneMatchMedia = mainWindow.matchMedia('(display-mode: standalone) or (display-mode: window-controls-overlay)');
const fullScreenMatchMedia = mainWindow.matchMedia('(display-mode: fullscreen)');
standalone = standaloneMatchMedia.matches;
addMatchMediaChangeListener(mainWindow, standaloneMatchMedia, ({ matches }) => {
// entering fullscreen would change standaloneMatchMedia.matches to false
// if standalone is true (running as PWA) and entering fullscreen, skip this change
if (standalone && fullScreenMatchMedia.matches) {
return;
}
// otherwise update standalone (browser to PWA or PWA to browser)
standalone = matches;
});
}
function getMonacoEnvironment() {
return globalThis.MonacoEnvironment;
}
export { addMatchMediaChangeListener, getMonacoEnvironment, getZoomFactor, isAndroid, isChrome, isFirefox, isSafari, isWebKit, isWebkitWebView };
+23
View File
@@ -0,0 +1,23 @@
import './browser.js';
import { mainWindow } from './window.js';
import { isNative } from '../common/platform.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Browser feature we can support in current platform, browser and environment.
*/
const BrowserFeatures = {
clipboard: {
writeText: (isNative
|| (document.queryCommandSupported && document.queryCommandSupported('copy'))
|| !!(navigator && navigator.clipboard && navigator.clipboard.writeText)),
readText: (isNative
|| !!(navigator && navigator.clipboard && navigator.clipboard.readText))
},
pointerEvents: mainWindow.PointerEvent && ('ontouchstart' in mainWindow || navigator.maxTouchPoints > 0)
};
export { BrowserFeatures };
+69
View File
@@ -0,0 +1,69 @@
import { FileAccess } from '../common/network.js';
function asFragment(raw) {
return raw;
}
function asCssValueWithDefault(cssPropertyValue, dflt) {
if (cssPropertyValue !== undefined) {
const variableMatch = cssPropertyValue.match(/^\s*var\((.+)\)$/);
if (variableMatch) {
const varArguments = variableMatch[1].split(',', 2);
if (varArguments.length === 2) {
dflt = asCssValueWithDefault(varArguments[1].trim(), dflt);
}
return `var(${varArguments[0]}, ${dflt})`;
}
return cssPropertyValue;
}
return dflt;
}
function identValue(value) {
const out = value.replaceAll(/[^_\-a-z0-9]/gi, '');
if (out !== value) {
console.warn(`CSS ident value ${value} modified to ${out} to be safe for CSS`);
}
return asFragment(out);
}
function stringValue(value) {
return asFragment(`'${value.replaceAll(/'/g, '\\000027')}'`);
}
/**
* returns url('...')
*/
function asCSSUrl(uri) {
if (!uri) {
return asFragment(`url('')`);
}
return inline `url('${asFragment(CSS.escape(FileAccess.uriToBrowserUri(uri).toString(true)))}')`;
}
function className(value, escapingExpected = false) {
const out = CSS.escape(value);
if (!escapingExpected && out !== value) {
console.warn(`CSS class name ${value} modified to ${out} to be safe for CSS`);
}
return asFragment(out);
}
/**
* Template string tag that that constructs a CSS fragment.
*
* All expressions in the template must be css safe values.
*/
function inline(strings, ...values) {
return asFragment(strings.reduce((result, str, i) => {
const value = values[i] || '';
return result + str + value;
}, ''));
}
class Builder {
constructor() {
this._parts = [];
}
push(...parts) {
this._parts.push(...parts);
}
join(joiner = '\n') {
return asFragment(this._parts.join(joiner));
}
}
export { Builder, asCSSUrl, asCssValueWithDefault, className, identValue, inline, stringValue };
+21
View File
@@ -0,0 +1,21 @@
import { Mimes } from '../common/mime.js';
// Common data transfers
const DataTransfers = {
/**
* Application specific resource transfer type
*/
RESOURCES: 'ResourceURLs',
/**
* Typically transfer type for copy/paste transfers.
*/
TEXT: Mimes.text,
/**
* Internal type used to pass around text/uri-list data.
*
* This is needed to work around https://bugs.chromium.org/p/chromium/issues/detail?id=239745.
*/
INTERNAL_URI_LIST: 'application/vnd.code.uri-list',
};
export { DataTransfers };
File diff suppressed because it is too large. Load diff
+312
View File
@@ -0,0 +1,312 @@
import { Schemas } from '../common/network.js';
import { reset } from './dom.js';
import purify from './dompurify/dompurify.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* List of safe, non-input html tags.
*/
const basicMarkupHtmlTags = Object.freeze([
'a',
'abbr',
'b',
'bdo',
'blockquote',
'br',
'caption',
'cite',
'code',
'col',
'colgroup',
'dd',
'del',
'details',
'dfn',
'div',
'dl',
'dt',
'em',
'figcaption',
'figure',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'hr',
'i',
'img',
'ins',
'kbd',
'label',
'li',
'mark',
'ol',
'p',
'pre',
'q',
'rp',
'rt',
'ruby',
's',
'samp',
'small',
'small',
'source',
'span',
'strike',
'strong',
'sub',
'summary',
'sup',
'table',
'tbody',
'td',
'tfoot',
'th',
'thead',
'time',
'tr',
'tt',
'u',
'ul',
'var',
'video',
'wbr',
]);
const defaultAllowedAttrs = Object.freeze([
'href',
'target',
'src',
'alt',
'title',
'for',
'name',
'role',
'tabindex',
'x-dispatch',
'required',
'checked',
'placeholder',
'type',
'start',
'width',
'height',
'align',
]);
const fakeRelativeUrlProtocol = 'vscode-relative-path';
function validateLink(value, allowedProtocols) {
if (allowedProtocols.override === '*') {
return true; // allow all protocols
}
try {
const url = new URL(value, fakeRelativeUrlProtocol + '://');
if (allowedProtocols.override.includes(url.protocol.replace(/:$/, ''))) {
return true;
}
if (allowedProtocols.allowRelativePaths
&& url.protocol === fakeRelativeUrlProtocol + ':'
&& !value.trim().toLowerCase().startsWith(fakeRelativeUrlProtocol)) {
return true;
}
return false;
}
catch (e) {
return false;
}
}
/**
* Hooks dompurify using `afterSanitizeAttributes` to check that all `href` and `src`
* attributes are valid.
*/
function hookDomPurifyHrefAndSrcSanitizer(allowedLinkProtocols, allowedMediaProtocols) {
purify.addHook('afterSanitizeAttributes', (node) => {
// check all href/src attributes for validity
for (const attr of ['href', 'src']) {
if (node.hasAttribute(attr)) {
const attrValue = node.getAttribute(attr);
if (attr === 'href') {
if (!attrValue.startsWith('#') && !validateLink(attrValue, allowedLinkProtocols)) {
node.removeAttribute(attr);
}
}
else { // 'src'
if (!validateLink(attrValue, allowedMediaProtocols)) {
node.removeAttribute(attr);
}
}
}
}
});
}
const defaultDomPurifyConfig = Object.freeze({
ALLOWED_TAGS: [...basicMarkupHtmlTags],
ALLOWED_ATTR: [...defaultAllowedAttrs],
// We sanitize the src/href attributes later if needed
ALLOW_UNKNOWN_PROTOCOLS: true,
});
/**
* Sanitizes an html string.
*
* @param untrusted The HTML string to sanitize.
* @param config Optional configuration for sanitization. If not provided, defaults to a safe configuration.
*
* @returns A sanitized string of html.
*/
function sanitizeHtml(untrusted, config) {
return doSanitizeHtml(untrusted, config, 'trusted');
}
function doSanitizeHtml(untrusted, config, outputType) {
try {
const resolvedConfig = { ...defaultDomPurifyConfig };
if (config?.allowedTags) {
if (config.allowedTags.override) {
resolvedConfig.ALLOWED_TAGS = [...config.allowedTags.override];
}
if (config.allowedTags.augment) {
resolvedConfig.ALLOWED_TAGS = [...(resolvedConfig.ALLOWED_TAGS ?? []), ...config.allowedTags.augment];
}
}
let resolvedAttributes = [...defaultAllowedAttrs];
if (config?.allowedAttributes) {
if (config.allowedAttributes.override) {
resolvedAttributes = [...config.allowedAttributes.override];
}
if (config.allowedAttributes.augment) {
resolvedAttributes = [...resolvedAttributes, ...config.allowedAttributes.augment];
}
}
// All attr names are lower-case in the sanitizer hooks
resolvedAttributes = resolvedAttributes.map((attr) => {
if (typeof attr === 'string') {
return attr.toLowerCase();
}
return {
attributeName: attr.attributeName.toLowerCase(),
shouldKeep: attr.shouldKeep,
};
});
const allowedAttrNames = new Set(resolvedAttributes.map(attr => typeof attr === 'string' ? attr : attr.attributeName));
const allowedAttrPredicates = new Map();
for (const attr of resolvedAttributes) {
if (typeof attr === 'string') {
// New string attribute value clears previously set predicates
allowedAttrPredicates.delete(attr);
}
else {
allowedAttrPredicates.set(attr.attributeName, attr);
}
}
resolvedConfig.ALLOWED_ATTR = Array.from(allowedAttrNames);
hookDomPurifyHrefAndSrcSanitizer({
override: config?.allowedLinkProtocols?.override ?? [Schemas.http, Schemas.https],
allowRelativePaths: config?.allowRelativeLinkPaths ?? false
}, {
override: config?.allowedMediaProtocols?.override ?? [Schemas.http, Schemas.https],
allowRelativePaths: config?.allowRelativeMediaPaths ?? false
});
if (config?.replaceWithPlaintext) {
purify.addHook('uponSanitizeElement', replaceWithPlainTextHook);
}
if (allowedAttrPredicates.size) {
purify.addHook('uponSanitizeAttribute', (node, e) => {
const predicate = allowedAttrPredicates.get(e.attrName);
if (predicate) {
const result = predicate.shouldKeep(node, e);
if (typeof result === 'string') {
e.keepAttr = true;
e.attrValue = result;
}
else {
e.keepAttr = result;
}
}
else {
e.keepAttr = allowedAttrNames.has(e.attrName);
}
});
}
if (outputType === 'dom') {
return purify.sanitize(untrusted, {
...resolvedConfig,
RETURN_DOM_FRAGMENT: true
});
}
else {
return purify.sanitize(untrusted, {
...resolvedConfig,
RETURN_TRUSTED_TYPE: true
}); // Cast from lib TrustedHTML to global TrustedHTML
}
}
finally {
purify.removeAllHooks();
}
}
const selfClosingTags = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
const replaceWithPlainTextHook = (node, data, _config) => {
if (!data.allowedTags[data.tagName] && data.tagName !== 'body') {
const replacement = convertTagToPlaintext(node);
if (replacement) {
if (node.nodeType === Node.COMMENT_NODE) {
// Workaround for https://github.com/cure53/DOMPurify/issues/1005
// The comment will be deleted in the next phase. However if we try to remove it now, it will cause
// an exception. Instead we insert the text node before the comment.
node.parentElement?.insertBefore(replacement, node);
}
else {
node.parentElement?.replaceChild(replacement, node);
}
}
}
};
function convertTagToPlaintext(node) {
if (!node.ownerDocument) {
return;
}
let startTagText;
let endTagText;
if (node.nodeType === Node.COMMENT_NODE) {
startTagText = `<!--${node.textContent}-->`;
}
else if (node instanceof Element) {
const tagName = node.tagName.toLowerCase();
const isSelfClosing = selfClosingTags.includes(tagName);
const attrString = node.attributes.length ?
' ' + Array.from(node.attributes)
.map(attr => `${attr.name}="${attr.value}"`)
.join(' ')
: '';
startTagText = `<${tagName}${attrString}>`;
if (!isSelfClosing) {
endTagText = `</${tagName}>`;
}
}
else {
return;
}
const fragment = document.createDocumentFragment();
const textNode = node.ownerDocument.createTextNode(startTagText);
fragment.appendChild(textNode);
while (node.firstChild) {
fragment.appendChild(node.firstChild);
}
const endTagTextNode = endTagText ? node.ownerDocument.createTextNode(endTagText) : undefined;
if (endTagTextNode) {
fragment.appendChild(endTagTextNode);
}
return fragment;
}
/**
* Sanitizes the given `value` and reset the given `node` with it.
*/
function safeSetInnerHtml(node, untrusted, config) {
const fragment = doSanitizeHtml(untrusted, config, 'dom');
reset(node, fragment);
}
export { basicMarkupHtmlTags, convertTagToPlaintext, defaultAllowedAttrs, safeSetInnerHtml, sanitizeHtml };
@@ -0,0 +1,145 @@
import { DisposableStore, toDisposable } from '../common/lifecycle.js';
import '../common/observableInternal/index.js';
import { isFirefox } from './browser.js';
import { getWindows, sharedMutationObserver } from './dom.js';
import { mainWindow } from './window.js';
import { autorun } from '../common/observableInternal/reactions/autorun.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const globalStylesheets = new Map();
/**
* A version of createStyleSheet which has a unified API to initialize/set the style content.
*/
function createStyleSheet2() {
return new WrappedStyleElement();
}
class WrappedStyleElement {
constructor() {
this._currentCssStyle = '';
this._styleSheet = undefined;
}
setStyle(cssStyle) {
if (cssStyle === this._currentCssStyle) {
return;
}
this._currentCssStyle = cssStyle;
if (!this._styleSheet) {
this._styleSheet = createStyleSheet(mainWindow.document.head, (s) => s.textContent = cssStyle);
}
else {
this._styleSheet.textContent = cssStyle;
}
}
dispose() {
if (this._styleSheet) {
this._styleSheet.remove();
this._styleSheet = undefined;
}
}
}
function createStyleSheet(container = mainWindow.document.head, beforeAppend, disposableStore) {
const style = document.createElement('style');
style.type = 'text/css';
style.media = 'screen';
beforeAppend?.(style);
container.appendChild(style);
if (disposableStore) {
disposableStore.add(toDisposable(() => style.remove()));
}
// With <head> as container, the stylesheet becomes global and is tracked
// to support auxiliary windows to clone the stylesheet.
if (container === mainWindow.document.head) {
const globalStylesheetClones = new Set();
globalStylesheets.set(style, globalStylesheetClones);
if (disposableStore) {
disposableStore.add(toDisposable(() => globalStylesheets.delete(style)));
}
for (const { window: targetWindow, disposables } of getWindows()) {
if (targetWindow === mainWindow) {
continue; // main window is already tracked
}
const cloneDisposable = disposables.add(cloneGlobalStyleSheet(style, globalStylesheetClones, targetWindow));
disposableStore?.add(cloneDisposable);
}
}
return style;
}
function cloneGlobalStyleSheet(globalStylesheet, globalStylesheetClones, targetWindow) {
const disposables = new DisposableStore();
const clone = globalStylesheet.cloneNode(true);
targetWindow.document.head.appendChild(clone);
disposables.add(toDisposable(() => clone.remove()));
for (const rule of getDynamicStyleSheetRules(globalStylesheet)) {
clone.sheet?.insertRule(rule.cssText, clone.sheet?.cssRules.length);
}
disposables.add(sharedMutationObserver.observe(globalStylesheet, disposables, { childList: true, subtree: isFirefox, characterData: isFirefox })(() => {
clone.textContent = globalStylesheet.textContent;
}));
globalStylesheetClones.add(clone);
disposables.add(toDisposable(() => globalStylesheetClones.delete(clone)));
return disposables;
}
let _sharedStyleSheet = null;
function getSharedStyleSheet() {
if (!_sharedStyleSheet) {
_sharedStyleSheet = createStyleSheet();
}
return _sharedStyleSheet;
}
function getDynamicStyleSheetRules(style) {
if (style?.sheet?.rules) {
// Chrome, IE
return style.sheet.rules;
}
if (style?.sheet?.cssRules) {
// FF
return style.sheet.cssRules;
}
return [];
}
function createCSSRule(selector, cssText, style = getSharedStyleSheet()) {
if (!style || !cssText) {
return;
}
style.sheet?.insertRule(`${selector} {${cssText}}`, 0);
// Apply rule also to all cloned global stylesheets
for (const clonedGlobalStylesheet of globalStylesheets.get(style) ?? []) {
createCSSRule(selector, cssText, clonedGlobalStylesheet);
}
}
function removeCSSRulesContainingSelector(ruleName, style = getSharedStyleSheet()) {
if (!style) {
return;
}
const rules = getDynamicStyleSheetRules(style);
const toDelete = [];
for (let i = 0; i < rules.length; i++) {
const rule = rules[i];
if (isCSSStyleRule(rule) && rule.selectorText.indexOf(ruleName) !== -1) {
toDelete.push(i);
}
}
for (let i = toDelete.length - 1; i >= 0; i--) {
style.sheet?.deleteRule(toDelete[i]);
}
// Remove rules also from all cloned global stylesheets
for (const clonedGlobalStylesheet of globalStylesheets.get(style) ?? []) {
removeCSSRulesContainingSelector(ruleName, clonedGlobalStylesheet);
}
}
function isCSSStyleRule(rule) {
return typeof rule.selectorText === 'string';
}
function createStyleSheetFromObservable(css) {
const store = new DisposableStore();
const w = store.add(createStyleSheet2());
store.add(autorun(reader => {
w.setStyle(css.read(reader));
}));
return store;
}
export { createCSSRule, createStyleSheet, createStyleSheet2, createStyleSheetFromObservable, removeCSSRulesContainingSelector };
File diff suppressed because it is too large. Load diff
+23
View File
@@ -0,0 +1,23 @@
import { Emitter } from '../common/event.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class DomEmitter {
get event() {
return this.emitter.event;
}
constructor(element, type, useCapture) {
const fn = (e) => this.emitter.fire(e);
this.emitter = new Emitter({
onWillAddFirstListener: () => element.addEventListener(type, fn, useCapture),
onDidRemoveLastListener: () => element.removeEventListener(type, fn, useCapture)
});
}
dispose() {
this.emitter.dispose();
}
}
export { DomEmitter };
+255
View File
@@ -0,0 +1,255 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class FastDomNode {
constructor(domNode) {
this.domNode = domNode;
this._maxWidth = '';
this._width = '';
this._height = '';
this._top = '';
this._left = '';
this._bottom = '';
this._right = '';
this._paddingLeft = '';
this._fontFamily = '';
this._fontWeight = '';
this._fontSize = '';
this._fontStyle = '';
this._fontFeatureSettings = '';
this._fontVariationSettings = '';
this._textDecoration = '';
this._lineHeight = '';
this._letterSpacing = '';
this._className = '';
this._display = '';
this._position = '';
this._visibility = '';
this._color = '';
this._backgroundColor = '';
this._layerHint = false;
this._contain = 'none';
this._boxShadow = '';
}
focus() {
this.domNode.focus();
}
setMaxWidth(_maxWidth) {
const maxWidth = numberAsPixels(_maxWidth);
if (this._maxWidth === maxWidth) {
return;
}
this._maxWidth = maxWidth;
this.domNode.style.maxWidth = this._maxWidth;
}
setWidth(_width) {
const width = numberAsPixels(_width);
if (this._width === width) {
return;
}
this._width = width;
this.domNode.style.width = this._width;
}
setHeight(_height) {
const height = numberAsPixels(_height);
if (this._height === height) {
return;
}
this._height = height;
this.domNode.style.height = this._height;
}
setTop(_top) {
const top = numberAsPixels(_top);
if (this._top === top) {
return;
}
this._top = top;
this.domNode.style.top = this._top;
}
setLeft(_left) {
const left = numberAsPixels(_left);
if (this._left === left) {
return;
}
this._left = left;
this.domNode.style.left = this._left;
}
setBottom(_bottom) {
const bottom = numberAsPixels(_bottom);
if (this._bottom === bottom) {
return;
}
this._bottom = bottom;
this.domNode.style.bottom = this._bottom;
}
setRight(_right) {
const right = numberAsPixels(_right);
if (this._right === right) {
return;
}
this._right = right;
this.domNode.style.right = this._right;
}
setPaddingLeft(_paddingLeft) {
const paddingLeft = numberAsPixels(_paddingLeft);
if (this._paddingLeft === paddingLeft) {
return;
}
this._paddingLeft = paddingLeft;
this.domNode.style.paddingLeft = this._paddingLeft;
}
setFontFamily(fontFamily) {
if (this._fontFamily === fontFamily) {
return;
}
this._fontFamily = fontFamily;
this.domNode.style.fontFamily = this._fontFamily;
}
setFontWeight(fontWeight) {
if (this._fontWeight === fontWeight) {
return;
}
this._fontWeight = fontWeight;
this.domNode.style.fontWeight = this._fontWeight;
}
setFontSize(_fontSize) {
const fontSize = numberAsPixels(_fontSize);
if (this._fontSize === fontSize) {
return;
}
this._fontSize = fontSize;
this.domNode.style.fontSize = this._fontSize;
}
setFontStyle(fontStyle) {
if (this._fontStyle === fontStyle) {
return;
}
this._fontStyle = fontStyle;
this.domNode.style.fontStyle = this._fontStyle;
}
setFontFeatureSettings(fontFeatureSettings) {
if (this._fontFeatureSettings === fontFeatureSettings) {
return;
}
this._fontFeatureSettings = fontFeatureSettings;
this.domNode.style.fontFeatureSettings = this._fontFeatureSettings;
}
setFontVariationSettings(fontVariationSettings) {
if (this._fontVariationSettings === fontVariationSettings) {
return;
}
this._fontVariationSettings = fontVariationSettings;
this.domNode.style.fontVariationSettings = this._fontVariationSettings;
}
setTextDecoration(textDecoration) {
if (this._textDecoration === textDecoration) {
return;
}
this._textDecoration = textDecoration;
this.domNode.style.textDecoration = this._textDecoration;
}
setLineHeight(_lineHeight) {
const lineHeight = numberAsPixels(_lineHeight);
if (this._lineHeight === lineHeight) {
return;
}
this._lineHeight = lineHeight;
this.domNode.style.lineHeight = this._lineHeight;
}
setLetterSpacing(_letterSpacing) {
const letterSpacing = numberAsPixels(_letterSpacing);
if (this._letterSpacing === letterSpacing) {
return;
}
this._letterSpacing = letterSpacing;
this.domNode.style.letterSpacing = this._letterSpacing;
}
setClassName(className) {
if (this._className === className) {
return;
}
this._className = className;
this.domNode.className = this._className;
}
toggleClassName(className, shouldHaveIt) {
this.domNode.classList.toggle(className, shouldHaveIt);
this._className = this.domNode.className;
}
setDisplay(display) {
if (this._display === display) {
return;
}
this._display = display;
this.domNode.style.display = this._display;
}
setPosition(position) {
if (this._position === position) {
return;
}
this._position = position;
this.domNode.style.position = this._position;
}
setVisibility(visibility) {
if (this._visibility === visibility) {
return;
}
this._visibility = visibility;
this.domNode.style.visibility = this._visibility;
}
setColor(color) {
if (this._color === color) {
return;
}
this._color = color;
this.domNode.style.color = this._color;
}
setBackgroundColor(backgroundColor) {
if (this._backgroundColor === backgroundColor) {
return;
}
this._backgroundColor = backgroundColor;
this.domNode.style.backgroundColor = this._backgroundColor;
}
setLayerHinting(layerHint) {
if (this._layerHint === layerHint) {
return;
}
this._layerHint = layerHint;
this.domNode.style.transform = this._layerHint ? 'translate3d(0px, 0px, 0px)' : '';
}
setBoxShadow(boxShadow) {
if (this._boxShadow === boxShadow) {
return;
}
this._boxShadow = boxShadow;
this.domNode.style.boxShadow = boxShadow;
}
setContain(contain) {
if (this._contain === contain) {
return;
}
this._contain = contain;
this.domNode.style.contain = this._contain;
}
setAttribute(name, value) {
this.domNode.setAttribute(name, value);
}
removeAttribute(name) {
this.domNode.removeAttribute(name);
}
appendChild(child) {
this.domNode.appendChild(child.domNode);
}
removeChild(child) {
this.domNode.removeChild(child.domNode);
}
}
function numberAsPixels(value) {
return (typeof value === 'number' ? `${value}px` : value);
}
function createFastDomNode(domNode) {
return new FastDomNode(domNode);
}
export { FastDomNode, createFastDomNode };
+17
View File
@@ -0,0 +1,17 @@
import { isWindows, isMacintosh } from '../common/platform.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* The best font-family to be used in CSS based on the platform:
* - Windows: Segoe preferred, fallback to sans-serif
* - macOS: standard system font, fallback to sans-serif
* - Linux: standard system font preferred, fallback to Ubuntu fonts
*
* Note: this currently does not adjust for different locales.
*/
const DEFAULT_FONT_FAMILY = isWindows ? '"Segoe WPC", "Segoe UI", sans-serif' : isMacintosh ? '-apple-system, BlinkMacSystemFont, sans-serif' : 'system-ui, "Ubuntu", "Droid Sans", sans-serif';
export { DEFAULT_FONT_FAMILY };
@@ -0,0 +1,160 @@
import { addStandardDisposableListener } from './dom.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
function renderText(text, _options, target) {
const element = target ?? document.createElement('div');
element.textContent = text;
return element;
}
function renderFormattedText(formattedText, options, target) {
const element = target ?? document.createElement('div');
element.textContent = '';
_renderFormattedText(element, parseFormattedText(formattedText), options?.actionHandler, options?.renderCodeSegments);
return element;
}
class StringStream {
constructor(source) {
this.source = source;
this.index = 0;
}
eos() {
return this.index >= this.source.length;
}
next() {
const next = this.peek();
this.advance();
return next;
}
peek() {
return this.source[this.index];
}
advance() {
this.index++;
}
}
function _renderFormattedText(element, treeNode, actionHandler, renderCodeSegments) {
let child;
if (treeNode.type === 2 /* FormatType.Text */) {
child = document.createTextNode(treeNode.content || '');
}
else if (treeNode.type === 3 /* FormatType.Bold */) {
child = document.createElement('b');
}
else if (treeNode.type === 4 /* FormatType.Italics */) {
child = document.createElement('i');
}
else if (treeNode.type === 7 /* FormatType.Code */ && renderCodeSegments) {
child = document.createElement('code');
}
else if (treeNode.type === 5 /* FormatType.Action */ && actionHandler) {
const a = document.createElement('a');
actionHandler.disposables.add(addStandardDisposableListener(a, 'click', (event) => {
actionHandler.callback(String(treeNode.index), event);
}));
child = a;
}
else if (treeNode.type === 8 /* FormatType.NewLine */) {
child = document.createElement('br');
}
else if (treeNode.type === 1 /* FormatType.Root */) {
child = element;
}
if (child && element !== child) {
element.appendChild(child);
}
if (child && Array.isArray(treeNode.children)) {
treeNode.children.forEach((nodeChild) => {
_renderFormattedText(child, nodeChild, actionHandler, renderCodeSegments);
});
}
}
function parseFormattedText(content, parseCodeSegments) {
const root = {
type: 1 /* FormatType.Root */,
children: []
};
let actionViewItemIndex = 0;
let current = root;
const stack = [];
const stream = new StringStream(content);
while (!stream.eos()) {
let next = stream.next();
const isEscapedFormatType = (next === '\\' && formatTagType(stream.peek()) !== 0 /* FormatType.Invalid */);
if (isEscapedFormatType) {
next = stream.next(); // unread the backslash if it escapes a format tag type
}
if (!isEscapedFormatType && isFormatTag(next) && next === stream.peek()) {
stream.advance();
if (current.type === 2 /* FormatType.Text */) {
current = stack.pop();
}
const type = formatTagType(next);
if (current.type === type || (current.type === 5 /* FormatType.Action */ && type === 6 /* FormatType.ActionClose */)) {
current = stack.pop();
}
else {
const newCurrent = {
type: type,
children: []
};
if (type === 5 /* FormatType.Action */) {
newCurrent.index = actionViewItemIndex;
actionViewItemIndex++;
}
current.children.push(newCurrent);
stack.push(current);
current = newCurrent;
}
}
else if (next === '\n') {
if (current.type === 2 /* FormatType.Text */) {
current = stack.pop();
}
current.children.push({
type: 8 /* FormatType.NewLine */
});
}
else {
if (current.type !== 2 /* FormatType.Text */) {
const textCurrent = {
type: 2 /* FormatType.Text */,
content: next
};
current.children.push(textCurrent);
stack.push(current);
current = textCurrent;
}
else {
current.content += next;
}
}
}
if (current.type === 2 /* FormatType.Text */) {
current = stack.pop();
}
return root;
}
function isFormatTag(char, supportCodeSegments) {
return formatTagType(char) !== 0 /* FormatType.Invalid */;
}
function formatTagType(char, supportCodeSegments) {
switch (char) {
case '*':
return 3 /* FormatType.Bold */;
case '_':
return 4 /* FormatType.Italics */;
case '[':
return 5 /* FormatType.Action */;
case ']':
return 6 /* FormatType.ActionClose */;
case '`':
return 0 /* FormatType.Invalid */;
default:
return 0 /* FormatType.Invalid */;
}
}
export { renderFormattedText, renderText };
@@ -0,0 +1,83 @@
import { getWindow, addDisposableListener, EventType } from './dom.js';
import { DisposableStore, toDisposable } from '../common/lifecycle.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class GlobalPointerMoveMonitor {
constructor() {
this._hooks = new DisposableStore();
this._pointerMoveCallback = null;
this._onStopCallback = null;
}
dispose() {
this.stopMonitoring(false);
this._hooks.dispose();
}
stopMonitoring(invokeStopCallback, browserEvent) {
if (!this.isMonitoring()) {
// Not monitoring
return;
}
// Unhook
this._hooks.clear();
this._pointerMoveCallback = null;
const onStopCallback = this._onStopCallback;
this._onStopCallback = null;
if (invokeStopCallback && onStopCallback) {
onStopCallback(browserEvent);
}
}
isMonitoring() {
return !!this._pointerMoveCallback;
}
startMonitoring(initialElement, pointerId, initialButtons, pointerMoveCallback, onStopCallback) {
if (this.isMonitoring()) {
this.stopMonitoring(false);
}
this._pointerMoveCallback = pointerMoveCallback;
this._onStopCallback = onStopCallback;
let eventSource = initialElement;
try {
initialElement.setPointerCapture(pointerId);
this._hooks.add(toDisposable(() => {
try {
initialElement.releasePointerCapture(pointerId);
}
catch (err) {
// See https://github.com/microsoft/vscode/issues/161731
//
// `releasePointerCapture` sometimes fails when being invoked with the exception:
// DOMException: Failed to execute 'releasePointerCapture' on 'Element':
// No active pointer with the given id is found.
//
// There's no need to do anything in case of failure
}
}));
}
catch (err) {
// See https://github.com/microsoft/vscode/issues/144584
// See https://github.com/microsoft/vscode/issues/146947
// `setPointerCapture` sometimes fails when being invoked
// from a `mousedown` listener on macOS and Windows
// and it always fails on Linux with the exception:
// DOMException: Failed to execute 'setPointerCapture' on 'Element':
// No active pointer with the given id is found.
// In case of failure, we bind the listeners on the window
eventSource = getWindow(initialElement);
}
this._hooks.add(addDisposableListener(eventSource, EventType.POINTER_MOVE, (e) => {
if (e.buttons !== initialButtons) {
// Buttons state has changed in the meantime
this.stopMonitoring(true);
return;
}
e.preventDefault();
this._pointerMoveCallback(e);
}));
this._hooks.add(addDisposableListener(eventSource, EventType.POINTER_UP, (e) => this.stopMonitoring(true)));
}
}
export { GlobalPointerMoveMonitor };
+87
View File
@@ -0,0 +1,87 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const sameOriginWindowChainCache = new WeakMap();
function getParentWindowIfSameOrigin(w) {
if (!w.parent || w.parent === w) {
return null;
}
// Cannot really tell if we have access to the parent window unless we try to access something in it
try {
const location = w.location;
const parentLocation = w.parent.location;
if (location.origin !== 'null' && parentLocation.origin !== 'null' && location.origin !== parentLocation.origin) {
return null;
}
}
catch (e) {
return null;
}
return w.parent;
}
class IframeUtils {
/**
* Returns a chain of embedded windows with the same origin (which can be accessed programmatically).
* Having a chain of length 1 might mean that the current execution environment is running outside of an iframe or inside an iframe embedded in a window with a different origin.
*/
static getSameOriginWindowChain(targetWindow) {
let windowChainCache = sameOriginWindowChainCache.get(targetWindow);
if (!windowChainCache) {
windowChainCache = [];
sameOriginWindowChainCache.set(targetWindow, windowChainCache);
let w = targetWindow;
let parent;
do {
parent = getParentWindowIfSameOrigin(w);
if (parent) {
windowChainCache.push({
window: new WeakRef(w),
iframeElement: w.frameElement || null
});
}
else {
windowChainCache.push({
window: new WeakRef(w),
iframeElement: null
});
}
w = parent;
} while (w);
}
return windowChainCache.slice(0);
}
/**
* Returns the position of `childWindow` relative to `ancestorWindow`
*/
static getPositionOfChildWindowRelativeToAncestorWindow(childWindow, ancestorWindow) {
if (!ancestorWindow || childWindow === ancestorWindow) {
return {
top: 0,
left: 0
};
}
let top = 0, left = 0;
const windowChain = this.getSameOriginWindowChain(childWindow);
for (const windowChainEl of windowChain) {
const windowInChain = windowChainEl.window.deref();
top += windowInChain?.scrollY ?? 0;
left += windowInChain?.scrollX ?? 0;
if (windowInChain === ancestorWindow) {
break;
}
if (!windowChainEl.iframeElement) {
break;
}
const boundingRect = windowChainEl.iframeElement.getBoundingClientRect();
top += boundingRect.top;
left += boundingRect.left;
}
return {
top: top,
left: left
};
}
}
export { IframeUtils };
@@ -0,0 +1,125 @@
import { isFirefox, isWebKit } from './browser.js';
import { KeyCodeUtils, EVENT_KEY_CODE_MAP } from '../common/keyCodes.js';
import { KeyCodeChord } from '../common/keybindings.js';
import { isMacintosh, isLinux } from '../common/platform.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
function extractKeyCode(e) {
if (e.charCode) {
// "keypress" events mostly
const char = String.fromCharCode(e.charCode).toUpperCase();
return KeyCodeUtils.fromString(char);
}
const keyCode = e.keyCode;
// browser quirks
if (keyCode === 3) {
return 7 /* KeyCode.PauseBreak */;
}
else if (isFirefox) {
switch (keyCode) {
case 59: return 85 /* KeyCode.Semicolon */;
case 60:
if (isLinux) {
return 97 /* KeyCode.IntlBackslash */;
}
break;
case 61: return 86 /* KeyCode.Equal */;
// based on: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#numpad_keys
case 107: return 109 /* KeyCode.NumpadAdd */;
case 109: return 111 /* KeyCode.NumpadSubtract */;
case 173: return 88 /* KeyCode.Minus */;
case 224:
if (isMacintosh) {
return 57 /* KeyCode.Meta */;
}
break;
}
}
else if (isWebKit) {
if (isMacintosh && keyCode === 93) {
// the two meta keys in the Mac have different key codes (91 and 93)
return 57 /* KeyCode.Meta */;
}
else if (!isMacintosh && keyCode === 92) {
return 57 /* KeyCode.Meta */;
}
}
// cross browser keycodes:
return EVENT_KEY_CODE_MAP[keyCode] || 0 /* KeyCode.Unknown */;
}
const ctrlKeyMod = (isMacintosh ? 256 /* KeyMod.WinCtrl */ : 2048 /* KeyMod.CtrlCmd */);
const altKeyMod = 512 /* KeyMod.Alt */;
const shiftKeyMod = 1024 /* KeyMod.Shift */;
const metaKeyMod = (isMacintosh ? 2048 /* KeyMod.CtrlCmd */ : 256 /* KeyMod.WinCtrl */);
class StandardKeyboardEvent {
constructor(source) {
this._standardKeyboardEventBrand = true;
const e = source;
this.browserEvent = e;
this.target = e.target;
this.ctrlKey = e.ctrlKey;
this.shiftKey = e.shiftKey;
this.altKey = e.altKey;
this.metaKey = e.metaKey;
this.altGraphKey = e.getModifierState?.('AltGraph');
this.keyCode = extractKeyCode(e);
this.code = e.code;
// console.info(e.type + ": keyCode: " + e.keyCode + ", which: " + e.which + ", charCode: " + e.charCode + ", detail: " + e.detail + " ====> " + this.keyCode + ' -- ' + KeyCode[this.keyCode]);
this.ctrlKey = this.ctrlKey || this.keyCode === 5 /* KeyCode.Ctrl */;
this.altKey = this.altKey || this.keyCode === 6 /* KeyCode.Alt */;
this.shiftKey = this.shiftKey || this.keyCode === 4 /* KeyCode.Shift */;
this.metaKey = this.metaKey || this.keyCode === 57 /* KeyCode.Meta */;
this._asKeybinding = this._computeKeybinding();
this._asKeyCodeChord = this._computeKeyCodeChord();
// console.log(`code: ${e.code}, keyCode: ${e.keyCode}, key: ${e.key}`);
}
preventDefault() {
if (this.browserEvent && this.browserEvent.preventDefault) {
this.browserEvent.preventDefault();
}
}
stopPropagation() {
if (this.browserEvent && this.browserEvent.stopPropagation) {
this.browserEvent.stopPropagation();
}
}
toKeyCodeChord() {
return this._asKeyCodeChord;
}
equals(other) {
return this._asKeybinding === other;
}
_computeKeybinding() {
let key = 0 /* KeyCode.Unknown */;
if (this.keyCode !== 5 /* KeyCode.Ctrl */ && this.keyCode !== 4 /* KeyCode.Shift */ && this.keyCode !== 6 /* KeyCode.Alt */ && this.keyCode !== 57 /* KeyCode.Meta */) {
key = this.keyCode;
}
let result = 0;
if (this.ctrlKey) {
result |= ctrlKeyMod;
}
if (this.altKey) {
result |= altKeyMod;
}
if (this.shiftKey) {
result |= shiftKeyMod;
}
if (this.metaKey) {
result |= metaKeyMod;
}
result |= key;
return result;
}
_computeKeyCodeChord() {
let key = 0 /* KeyCode.Unknown */;
if (this.keyCode !== 5 /* KeyCode.Ctrl */ && this.keyCode !== 4 /* KeyCode.Shift */ && this.keyCode !== 6 /* KeyCode.Alt */ && this.keyCode !== 57 /* KeyCode.Meta */) {
key = this.keyCode;
}
return new KeyCodeChord(this.ctrlKey, this.shiftKey, this.altKey, this.metaKey, key);
}
}
export { StandardKeyboardEvent };
@@ -0,0 +1,901 @@
import { onUnexpectedError } from '../common/errors.js';
import { removeMarkdownEscapes, escapeDoubleQuotes, parseHrefAndDimensions } from '../common/htmlContent.js';
import { markdownEscapeEscapedIcons } from '../common/iconLabels.js';
import { defaultGenerator } from '../common/idGenerator.js';
import { Lazy } from '../common/lazy.js';
import { DisposableStore } from '../common/lifecycle.js';
import { Renderer as _Renderer, Marked, lexer, parse as parse$1 } from '../common/marked/marked.js';
import { parse } from '../common/marshalling.js';
import { Schemas, FileAccess } from '../common/network.js';
import { cloneAndChange } from '../common/objects.js';
import { resolvePath, dirname } from '../common/resources.js';
import { escape } from '../common/strings.js';
import { URI } from '../common/uri.js';
import { reset, addDisposableListener, $, getWindow, isHTMLElement } from './dom.js';
import { basicMarkupHtmlTags, safeSetInnerHtml, convertTagToPlaintext, sanitizeHtml } from './domSanitize.js';
import { StandardKeyboardEvent } from './keyboardEvent.js';
import { StandardMouseEvent } from './mouseEvent.js';
import { renderLabelWithIcons, renderIcon } from './ui/iconLabel/iconLabels.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const defaultMarkedRenderers = Object.freeze({
image: ({ href, title, text }) => {
let dimensions = [];
let attributes = [];
if (href) {
({ href, dimensions } = parseHrefAndDimensions(href));
attributes.push(`src="${escapeDoubleQuotes(href)}"`);
}
if (text) {
attributes.push(`alt="${escapeDoubleQuotes(text)}"`);
}
if (title) {
attributes.push(`title="${escapeDoubleQuotes(title)}"`);
}
if (dimensions.length) {
attributes = attributes.concat(dimensions);
}
return '<img ' + attributes.join(' ') + '>';
},
paragraph({ tokens }) {
return `<p>${this.parser.parseInline(tokens)}</p>`;
},
link({ href, title, tokens }) {
let text = this.parser.parseInline(tokens);
if (typeof href !== 'string') {
return '';
}
// Remove markdown escapes. Workaround for https://github.com/chjj/marked/issues/829
if (href === text) { // raw link case
text = removeMarkdownEscapes(text);
}
title = typeof title === 'string' ? escapeDoubleQuotes(removeMarkdownEscapes(title)) : '';
href = removeMarkdownEscapes(href);
// HTML Encode href
href = href.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
return `<a href="${href}" title="${title || href}" draggable="false">${text}</a>`;
},
});
/**
* Blockquote renderer that processes GitHub-style alert syntax.
* Transforms blockquotes like "> [!NOTE]" into structured alert markup with icons.
*
* Based on GitHub's alert syntax: https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts
*/
function createAlertBlockquoteRenderer(fallbackRenderer) {
return function (token) {
const { tokens } = token;
// Check if this blockquote starts with alert syntax [!TYPE]
const firstToken = tokens[0];
if (firstToken?.type !== 'paragraph') {
return fallbackRenderer.call(this, token);
}
const paragraphTokens = firstToken.tokens;
if (!paragraphTokens || paragraphTokens.length === 0) {
return fallbackRenderer.call(this, token);
}
const firstTextToken = paragraphTokens[0];
if (firstTextToken?.type !== 'text') {
return fallbackRenderer.call(this, token);
}
const pattern = /^\s*\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]\s*?\n*/i;
const match = firstTextToken.raw.match(pattern);
if (!match) {
return fallbackRenderer.call(this, token);
}
// Remove the alert marker from the token
firstTextToken.raw = firstTextToken.raw.replace(pattern, '');
firstTextToken.text = firstTextToken.text.replace(pattern, '');
const alertIcons = {
'note': 'info',
'tip': 'light-bulb',
'important': 'comment',
'warning': 'alert',
'caution': 'stop'
};
const type = match[1];
const typeCapitalized = type.charAt(0).toUpperCase() + type.slice(1).toLowerCase();
const severity = type.toLowerCase();
const iconHtml = renderIcon({ id: alertIcons[severity] }).outerHTML;
// Render the remaining content
const content = this.parser.parse(tokens);
// Return alert markup with icon and severity (skipping the first 3 characters: `<p>`)
return `<blockquote data-severity="${severity}"><p><span>${iconHtml}${typeCapitalized}</span>${content.substring(3)}</blockquote>\n`;
};
}
/**
* Low-level way create a html element from a markdown string.
*
* **Note** that for most cases you should be using {@link import('../../editor/browser/widget/markdownRenderer/browser/markdownRenderer.js').MarkdownRenderer MarkdownRenderer}
* which comes with support for pretty code block rendering and which uses the default way of handling links.
*/
function renderMarkdown(markdown, options = {}, target) {
const disposables = new DisposableStore();
let isDisposed = false;
const markedInstance = new Marked(...(options.markedExtensions ?? []));
const { renderer, codeBlocks, syncCodeBlocks } = createMarkdownRenderer(markedInstance, options, markdown);
const value = preprocessMarkdownString(markdown);
let renderedMarkdown;
if (options.fillInIncompleteTokens) {
// The defaults are applied by parse but not lexer()/parser(), and they need to be present
const opts = {
...markedInstance.defaults,
...options.markedOptions,
renderer
};
const tokens = markedInstance.lexer(value, opts);
const newTokens = fillInIncompleteTokens(tokens);
renderedMarkdown = markedInstance.parser(newTokens, opts);
}
else {
renderedMarkdown = markedInstance.parse(value, { ...options?.markedOptions, renderer, async: false });
}
// Rewrite theme icons
if (markdown.supportThemeIcons) {
const elements = renderLabelWithIcons(renderedMarkdown);
renderedMarkdown = elements.map(e => typeof e === 'string' ? e : e.outerHTML).join('');
}
const renderedContent = document.createElement('div');
const sanitizerConfig = getDomSanitizerConfig(markdown, options.sanitizerConfig ?? {});
safeSetInnerHtml(renderedContent, renderedMarkdown, sanitizerConfig);
// Rewrite links and images before potentially inserting them into the real dom
rewriteRenderedLinks(markdown, options, renderedContent);
let outElement;
if (target) {
outElement = target;
reset(target, ...renderedContent.children);
}
else {
outElement = renderedContent;
}
if (codeBlocks.length > 0) {
Promise.all(codeBlocks).then((tuples) => {
if (isDisposed) {
return;
}
const renderedElements = new Map(tuples);
// eslint-disable-next-line no-restricted-syntax
const placeholderElements = outElement.querySelectorAll(`div[data-code]`);
for (const placeholderElement of placeholderElements) {
const renderedElement = renderedElements.get(placeholderElement.dataset['code'] ?? '');
if (renderedElement) {
reset(placeholderElement, renderedElement);
}
}
options.asyncRenderCallback?.();
});
}
else if (syncCodeBlocks.length > 0) {
const renderedElements = new Map(syncCodeBlocks);
// eslint-disable-next-line no-restricted-syntax
const placeholderElements = outElement.querySelectorAll(`div[data-code]`);
for (const placeholderElement of placeholderElements) {
const renderedElement = renderedElements.get(placeholderElement.dataset['code'] ?? '');
if (renderedElement) {
reset(placeholderElement, renderedElement);
}
}
}
// Signal size changes for image tags
if (options.asyncRenderCallback) {
// eslint-disable-next-line no-restricted-syntax
for (const img of outElement.getElementsByTagName('img')) {
const listener = disposables.add(addDisposableListener(img, 'load', () => {
listener.dispose();
options.asyncRenderCallback();
}));
}
}
// Add event listeners for links
if (options.actionHandler) {
const clickCb = (e) => {
const mouseEvent = new StandardMouseEvent(getWindow(outElement), e);
if (!mouseEvent.leftButton && !mouseEvent.middleButton) {
return;
}
activateLink(markdown, options, mouseEvent);
};
disposables.add(addDisposableListener(outElement, 'click', clickCb));
disposables.add(addDisposableListener(outElement, 'auxclick', clickCb));
disposables.add(addDisposableListener(outElement, 'keydown', (e) => {
const keyboardEvent = new StandardKeyboardEvent(e);
if (!keyboardEvent.equals(10 /* KeyCode.Space */) && !keyboardEvent.equals(3 /* KeyCode.Enter */)) {
return;
}
activateLink(markdown, options, keyboardEvent);
}));
}
// Remove/disable inputs
// eslint-disable-next-line no-restricted-syntax
for (const input of [...outElement.getElementsByTagName('input')]) {
if (input.attributes.getNamedItem('type')?.value === 'checkbox') {
input.setAttribute('disabled', '');
}
else {
if (options.sanitizerConfig?.replaceWithPlaintext) {
const replacement = convertTagToPlaintext(input);
if (replacement) {
input.parentElement?.replaceChild(replacement, input);
}
else {
input.remove();
}
}
else {
input.remove();
}
}
}
return {
element: outElement,
dispose: () => {
isDisposed = true;
disposables.dispose();
}
};
}
function rewriteRenderedLinks(markdown, options, root) {
// eslint-disable-next-line no-restricted-syntax
for (const el of root.querySelectorAll('img, audio, video, source')) {
const src = el.getAttribute('src'); // Get the raw 'src' attribute value as text, not the resolved 'src'
if (src) {
let href = src;
try {
if (markdown.baseUri) { // absolute or relative local path, or file: uri
href = resolveWithBaseUri(URI.from(markdown.baseUri), href);
}
}
catch (err) { }
el.setAttribute('src', massageHref(markdown, href, true));
if (options.sanitizerConfig?.remoteImageIsAllowed) {
const uri = URI.parse(href);
if (uri.scheme !== Schemas.file && uri.scheme !== Schemas.data && !options.sanitizerConfig.remoteImageIsAllowed(uri)) {
el.replaceWith($('', undefined, el.outerHTML));
}
}
}
}
// eslint-disable-next-line no-restricted-syntax
for (const el of root.querySelectorAll('a')) {
const href = el.getAttribute('href'); // Get the raw 'href' attribute value as text, not the resolved 'href'
el.setAttribute('href', ''); // Clear out href. We use the `data-href` for handling clicks instead
if (!href
|| /^data:|javascript:/i.test(href)
|| (/^command:/i.test(href) && !markdown.isTrusted)
|| /^command:(\/\/\/)?_workbench\.downloadResource/i.test(href)) {
// drop the link
el.replaceWith(...el.childNodes);
}
else {
let resolvedHref = massageHref(markdown, href, false);
if (markdown.baseUri) {
resolvedHref = resolveWithBaseUri(URI.from(markdown.baseUri), href);
}
el.dataset.href = resolvedHref;
}
}
}
function createMarkdownRenderer(marked, options, markdown) {
const renderer = new marked.Renderer(options.markedOptions);
renderer.image = defaultMarkedRenderers.image;
renderer.link = defaultMarkedRenderers.link;
renderer.paragraph = defaultMarkedRenderers.paragraph;
if (markdown.supportAlertSyntax) {
renderer.blockquote = createAlertBlockquoteRenderer(renderer.blockquote);
}
// Will collect [id, renderedElement] tuples
const codeBlocks = [];
const syncCodeBlocks = [];
if (options.codeBlockRendererSync) {
renderer.code = ({ text, lang, raw }) => {
const id = defaultGenerator.nextId();
const value = options.codeBlockRendererSync(postProcessCodeBlockLanguageId(lang), text, raw);
syncCodeBlocks.push([id, value]);
return `<div class="code" data-code="${id}">${escape(text)}</div>`;
};
}
else if (options.codeBlockRenderer) {
renderer.code = ({ text, lang }) => {
const id = defaultGenerator.nextId();
const value = options.codeBlockRenderer(postProcessCodeBlockLanguageId(lang), text);
codeBlocks.push(value.then(element => [id, element]));
return `<div class="code" data-code="${id}">${escape(text)}</div>`;
};
}
if (!markdown.supportHtml) {
// Note: we always pass the output through dompurify after this so that we don't rely on
// marked for real sanitization.
renderer.html = ({ text }) => {
if (options.sanitizerConfig?.replaceWithPlaintext) {
return escape(text);
}
const match = markdown.isTrusted ? text.match(/^(<span[^>]+>)|(<\/\s*span>)$/) : undefined;
return match ? text : '';
};
}
return { renderer, codeBlocks, syncCodeBlocks };
}
function preprocessMarkdownString(markdown) {
let value = markdown.value;
// values that are too long will freeze the UI
if (value.length > 100_000) {
value = `${value.substr(0, 100_000)}…`;
}
// escape theme icons
if (markdown.supportThemeIcons) {
value = markdownEscapeEscapedIcons(value);
}
return value;
}
function activateLink(mdStr, options, event) {
const target = event.target.closest('a[data-href]');
if (!isHTMLElement(target)) {
return;
}
try {
let href = target.dataset['href'];
if (href) {
if (mdStr.baseUri) {
href = resolveWithBaseUri(URI.from(mdStr.baseUri), href);
}
options.actionHandler?.(href, mdStr);
}
}
catch (err) {
onUnexpectedError(err);
}
finally {
event.preventDefault();
}
}
function uriMassage(markdown, part) {
let data;
try {
data = parse(decodeURIComponent(part));
}
catch (e) {
// ignore
}
if (!data) {
return part;
}
data = cloneAndChange(data, value => {
if (markdown.uris && markdown.uris[value]) {
return URI.revive(markdown.uris[value]);
}
else {
return undefined;
}
});
return encodeURIComponent(JSON.stringify(data));
}
function massageHref(markdown, href, isDomUri) {
const data = markdown.uris && markdown.uris[href];
let uri = URI.revive(data);
if (isDomUri) {
if (href.startsWith(Schemas.data + ':')) {
return href;
}
if (!uri) {
uri = URI.parse(href);
}
// this URI will end up as "src"-attribute of a dom node
// and because of that special rewriting needs to be done
// so that the URI uses a protocol that's understood by
// browsers (like http or https)
return FileAccess.uriToBrowserUri(uri).toString(true);
}
if (!uri) {
return href;
}
if (URI.parse(href).toString() === uri.toString()) {
return href; // no transformation performed
}
if (uri.query) {
uri = uri.with({ query: uriMassage(markdown, uri.query) });
}
return uri.toString();
}
function postProcessCodeBlockLanguageId(lang) {
if (!lang) {
return '';
}
const parts = lang.split(/[\s+|:|,|\{|\?]/, 1);
if (parts.length) {
return parts[0];
}
return lang;
}
function resolveWithBaseUri(baseUri, href) {
const hasScheme = /^\w[\w\d+.-]*:/.test(href);
if (hasScheme) {
return href;
}
if (baseUri.path.endsWith('/')) {
return resolvePath(baseUri, href).toString();
}
else {
return resolvePath(dirname(baseUri), href).toString();
}
}
function sanitizeRenderedMarkdown(renderedMarkdown, originalMdStrConfig, options = {}) {
const sanitizerConfig = getDomSanitizerConfig(originalMdStrConfig, options);
return sanitizeHtml(renderedMarkdown, sanitizerConfig);
}
const allowedMarkdownHtmlTags = Object.freeze([
...basicMarkupHtmlTags,
'input', // Allow inputs for rendering checkboxes. Other types of inputs are removed and the inputs are always disabled
]);
const allowedMarkdownHtmlAttributes = Object.freeze([
'align',
'autoplay',
'alt',
'colspan',
'controls',
'draggable',
'height',
'href',
'loop',
'muted',
'playsinline',
'poster',
'rowspan',
'src',
'target',
'title',
'type',
'width',
'start',
// Input (For disabled inputs)
'checked',
'disabled',
'value',
// Custom markdown attributes
'data-code',
'data-href',
'data-severity',
// Only allow very specific styles
{
attributeName: 'style',
shouldKeep: (element, data) => {
if (element.tagName === 'SPAN') {
if (data.attrName === 'style') {
return /^(color\:(#[0-9a-fA-F]+|var\(--vscode(-[a-zA-Z0-9]+)+\));)?(background-color\:(#[0-9a-fA-F]+|var\(--vscode(-[a-zA-Z0-9]+)+\));)?(border-radius:[0-9]+px;)?$/.test(data.attrValue);
}
}
return false;
}
},
// Only allow codicons for classes
{
attributeName: 'class',
shouldKeep: (element, data) => {
if (element.tagName === 'SPAN') {
if (data.attrName === 'class') {
return /^codicon codicon-[a-z\-]+( codicon-modifier-[a-z\-]+)?$/.test(data.attrValue);
}
}
return false;
},
},
]);
function getDomSanitizerConfig(mdStrConfig, options) {
const isTrusted = mdStrConfig.isTrusted ?? false;
const allowedLinkSchemes = [
Schemas.http,
Schemas.https,
Schemas.mailto,
Schemas.file,
Schemas.vscodeFileResource,
Schemas.vscodeRemote,
Schemas.vscodeRemoteResource,
Schemas.vscodeNotebookCell
];
if (isTrusted) {
allowedLinkSchemes.push(Schemas.command);
}
if (options.allowedLinkSchemes?.augment) {
allowedLinkSchemes.push(...options.allowedLinkSchemes.augment);
}
return {
// allowedTags should included everything that markdown renders to.
// Since we have our own sanitize function for marked, it's possible we missed some tag so let dompurify make sure.
// HTML tags that can result from markdown are from reading https://spec.commonmark.org/0.29/
// HTML table tags that can result from markdown are from https://github.github.com/gfm/#tables-extension-
allowedTags: {
override: options.allowedTags?.override ?? allowedMarkdownHtmlTags
},
allowedAttributes: {
override: options.allowedAttributes?.override ?? allowedMarkdownHtmlAttributes,
},
allowedLinkProtocols: {
override: allowedLinkSchemes,
},
allowRelativeLinkPaths: !!mdStrConfig.baseUri,
allowedMediaProtocols: {
override: [
Schemas.http,
Schemas.https,
Schemas.data,
Schemas.file,
Schemas.vscodeFileResource,
Schemas.vscodeRemote,
Schemas.vscodeRemoteResource,
]
},
allowRelativeMediaPaths: !!mdStrConfig.baseUri,
replaceWithPlaintext: options.replaceWithPlaintext,
};
}
/**
* Renders `str` as plaintext, stripping out Markdown syntax if it's a {@link IMarkdownString}.
*
* For example `# Header` would be output as `Header`.
*/
function renderAsPlaintext(str, options) {
if (typeof str === 'string') {
return str;
}
// values that are too long will freeze the UI
let value = str.value ?? '';
if (value.length > 100_000) {
value = `${value.substr(0, 100_000)}…`;
}
const html = parse$1(value, { async: false, renderer: plainTextRenderer.value });
return sanitizeRenderedMarkdown(html, { isTrusted: false }, {})
.toString()
.replace(/&(#\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m)
.trim();
}
const unescapeInfo = new Map([
['&quot;', '"'],
['&nbsp;', ' '],
['&amp;', '&'],
['&#39;', '\''],
['&lt;', '<'],
['&gt;', '>'],
]);
function createPlainTextRenderer() {
const renderer = new _Renderer();
renderer.code = ({ text }) => {
return escape(text);
};
renderer.blockquote = ({ text }) => {
return text + '\n';
};
renderer.html = (_) => {
return '';
};
renderer.heading = function ({ tokens }) {
return this.parser.parseInline(tokens) + '\n';
};
renderer.hr = () => {
return '';
};
renderer.list = function ({ items }) {
return items.map(x => this.listitem(x)).join('\n') + '\n';
};
renderer.listitem = ({ text }) => {
return text + '\n';
};
renderer.paragraph = function ({ tokens }) {
return this.parser.parseInline(tokens) + '\n';
};
renderer.table = function ({ header, rows }) {
return header.map(cell => this.tablecell(cell)).join(' ') + '\n' + rows.map(cells => cells.map(cell => this.tablecell(cell)).join(' ')).join('\n') + '\n';
};
renderer.tablerow = ({ text }) => {
return text;
};
renderer.tablecell = function ({ tokens }) {
return this.parser.parseInline(tokens);
};
renderer.strong = ({ text }) => {
return text;
};
renderer.em = ({ text }) => {
return text;
};
renderer.codespan = ({ text }) => {
return escape(text);
};
renderer.br = (_) => {
return '\n';
};
renderer.del = ({ text }) => {
return text;
};
renderer.image = (_) => {
return '';
};
renderer.text = ({ text }) => {
return text;
};
renderer.link = ({ text }) => {
return text;
};
return renderer;
}
const plainTextRenderer = new Lazy(createPlainTextRenderer);
new Lazy(() => {
const renderer = createPlainTextRenderer();
renderer.code = ({ text }) => {
return `\n\`\`\`\n${escape(text)}\n\`\`\`\n`;
};
return renderer;
});
function mergeRawTokenText(tokens) {
let mergedTokenText = '';
tokens.forEach(token => {
mergedTokenText += token.raw;
});
return mergedTokenText;
}
function completeSingleLinePattern(token) {
if (!token.tokens) {
return undefined;
}
for (let i = token.tokens.length - 1; i >= 0; i--) {
const subtoken = token.tokens[i];
if (subtoken.type === 'text') {
const lines = subtoken.raw.split('\n');
const lastLine = lines[lines.length - 1];
if (lastLine.includes('`')) {
return completeCodespan(token);
}
else if (lastLine.includes('**')) {
return completeDoublestar(token);
}
else if (lastLine.match(/\*\w/)) {
return completeStar(token);
}
else if (lastLine.match(/(^|\s)__\w/)) {
return completeDoubleUnderscore(token);
}
else if (lastLine.match(/(^|\s)_\w/)) {
return completeUnderscore(token);
}
else if (
// Text with start of link target
hasLinkTextAndStartOfLinkTarget(lastLine) ||
// This token doesn't have the link text, eg if it contains other markdown constructs that are in other subtokens.
// But some preceding token does have an unbalanced [ at least
hasStartOfLinkTargetAndNoLinkText(lastLine) && token.tokens.slice(0, i).some(t => t.type === 'text' && t.raw.match(/\[[^\]]*$/))) {
const nextTwoSubTokens = token.tokens.slice(i + 1);
// A markdown link can look like
// [link text](https://microsoft.com "more text")
// Where "more text" is a title for the link or an argument to a vscode command link
if (
// If the link was parsed as a link, then look for a link token and a text token with a quote
nextTwoSubTokens[0]?.type === 'link' && nextTwoSubTokens[1]?.type === 'text' && nextTwoSubTokens[1].raw.match(/^ *"[^"]*$/) ||
// And if the link was not parsed as a link (eg command link), just look for a single quote in this token
lastLine.match(/^[^"]* +"[^"]*$/)) {
return completeLinkTargetArg(token);
}
return completeLinkTarget(token);
}
// Contains the start of link text, and no following tokens contain the link target
else if (lastLine.match(/(^|\s)\[\w*[^\]]*$/)) {
return completeLinkText(token);
}
}
}
return undefined;
}
function hasLinkTextAndStartOfLinkTarget(str) {
return !!str.match(/(^|\s)\[.*\]\(\w*/);
}
function hasStartOfLinkTargetAndNoLinkText(str) {
return !!str.match(/^[^\[]*\]\([^\)]*$/);
}
function completeListItemPattern(list) {
// Patch up this one list item
const lastListItem = list.items[list.items.length - 1];
const lastListSubToken = lastListItem.tokens ? lastListItem.tokens[lastListItem.tokens.length - 1] : undefined;
/*
Example list token structures:
list
list_item
text
text
codespan
link
list_item
text
code // Complete indented codeblock
list_item
text
space
text
text // Incomplete indented codeblock
list_item
text
list // Nested list
list_item
text
text
Contrast with paragraph:
paragraph
text
codespan
*/
const listEndsInHeading = (list) => {
// A list item can be rendered as a heading for some reason when it has a subitem where we haven't rendered the text yet like this:
// 1. list item
// -
const lastItem = list.items.at(-1);
const lastToken = lastItem?.tokens.at(-1);
return lastToken?.type === 'heading' || lastToken?.type === 'list' && listEndsInHeading(lastToken);
};
let newToken;
if (lastListSubToken?.type === 'text' && !('inRawBlock' in lastListItem)) { // Why does Tag have a type of 'text'
newToken = completeSingleLinePattern(lastListSubToken);
}
else if (listEndsInHeading(list)) {
const newList = lexer(list.raw.trim() + ' &nbsp;')[0];
if (newList.type !== 'list') {
// Something went wrong
return;
}
return newList;
}
if (!newToken || newToken.type !== 'paragraph') { // 'text' item inside the list item turns into paragraph
// Nothing to fix, or not a pattern we were expecting
return;
}
const previousListItemsText = mergeRawTokenText(list.items.slice(0, -1));
// Grabbing the `- ` or `1. ` or `* ` off the list item because I can't find a better way to do this
const lastListItemLead = lastListItem.raw.match(/^(\s*(-|\d+\.|\*) +)/)?.[0];
if (!lastListItemLead) {
// Is badly formatted
return;
}
const newListItemText = lastListItemLead +
mergeRawTokenText(lastListItem.tokens.slice(0, -1)) +
newToken.raw;
const newList = lexer(previousListItemsText + newListItemText)[0];
if (newList.type !== 'list') {
// Something went wrong
return;
}
return newList;
}
function completeHeading(token, fullRawText) {
if (token.raw.match(/-\s*$/)) {
return lexer(fullRawText + ' &nbsp;');
}
}
const maxIncompleteTokensFixRounds = 3;
function fillInIncompleteTokens(tokens) {
for (let i = 0; i < maxIncompleteTokensFixRounds; i++) {
const newTokens = fillInIncompleteTokensOnce(tokens);
if (newTokens) {
tokens = newTokens;
}
else {
break;
}
}
return tokens;
}
function fillInIncompleteTokensOnce(tokens) {
let i;
let newTokens;
for (i = 0; i < tokens.length; i++) {
const token = tokens[i];
if (token.type === 'paragraph' && token.raw.match(/(\n|^)\|/)) {
newTokens = completeTable(tokens.slice(i));
break;
}
}
const lastToken = tokens.at(-1);
if (!newTokens && lastToken?.type === 'list') {
const newListToken = completeListItemPattern(lastToken);
if (newListToken) {
newTokens = [newListToken];
i = tokens.length - 1;
}
}
if (!newTokens && lastToken?.type === 'paragraph') {
// Only operates on a single token, because any newline that follows this should break these patterns
const newToken = completeSingleLinePattern(lastToken);
if (newToken) {
newTokens = [newToken];
i = tokens.length - 1;
}
}
if (newTokens) {
const newTokensList = [
...tokens.slice(0, i),
...newTokens
];
newTokensList.links = tokens.links;
return newTokensList;
}
if (lastToken?.type === 'heading') {
const completeTokens = completeHeading(lastToken, mergeRawTokenText(tokens));
if (completeTokens) {
return completeTokens;
}
}
return null;
}
function completeCodespan(token) {
return completeWithString(token, '`');
}
function completeStar(tokens) {
return completeWithString(tokens, '*');
}
function completeUnderscore(tokens) {
return completeWithString(tokens, '_');
}
function completeLinkTarget(tokens) {
return completeWithString(tokens, ')', false);
}
function completeLinkTargetArg(tokens) {
return completeWithString(tokens, '")', false);
}
function completeLinkText(tokens) {
return completeWithString(tokens, '](https://microsoft.com)', false);
}
function completeDoublestar(tokens) {
return completeWithString(tokens, '**');
}
function completeDoubleUnderscore(tokens) {
return completeWithString(tokens, '__');
}
function completeWithString(tokens, closingString, shouldTrim = true) {
const mergedRawText = mergeRawTokenText(Array.isArray(tokens) ? tokens : [tokens]);
// If it was completed correctly, this should be a single token.
// Expecting either a Paragraph or a List
const trimmedRawText = shouldTrim ? mergedRawText.trimEnd() : mergedRawText;
return lexer(trimmedRawText + closingString)[0];
}
function completeTable(tokens) {
const mergedRawText = mergeRawTokenText(tokens);
const lines = mergedRawText.split('\n');
let numCols; // The number of line1 col headers
let hasSeparatorRow = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (typeof numCols === 'undefined' && line.match(/^\s*\|/)) {
const line1Matches = line.match(/(\|[^\|]+)(?=\||$)/g);
if (line1Matches) {
numCols = line1Matches.length;
}
}
else if (typeof numCols === 'number') {
if (line.match(/^\s*\|/)) {
if (i !== lines.length - 1) {
// We got the line1 header row, and the line2 separator row, but there are more lines, and it wasn't parsed as a table!
// That's strange and means that the table is probably malformed in the source, so I won't try to patch it up.
return undefined;
}
// Got a line2 separator row- partial or complete, doesn't matter, we'll replace it with a correct one
hasSeparatorRow = true;
}
else {
// The line after the header row isn't a valid separator row, so the table is malformed, don't fix it up
return undefined;
}
}
}
if (typeof numCols === 'number' && numCols > 0) {
const prefixText = hasSeparatorRow ? lines.slice(0, -1).join('\n') : mergedRawText;
const line1EndsInPipe = !!prefixText.match(/\|\s*$/);
const newRawText = prefixText + (line1EndsInPipe ? '' : '|') + `\n|${' --- |'.repeat(numCols)}`;
return lexer(newRawText);
}
return undefined;
}
export { allowedMarkdownHtmlAttributes, allowedMarkdownHtmlTags, fillInIncompleteTokens, renderAsPlaintext, renderMarkdown };
+153
View File
@@ -0,0 +1,153 @@
import { isChrome, isFirefox, isSafari } from './browser.js';
import { IframeUtils } from './iframe.js';
import { isMacintosh, isWindows } from '../common/platform.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class StandardMouseEvent {
constructor(targetWindow, e) {
this.timestamp = Date.now();
this.browserEvent = e;
this.leftButton = e.button === 0;
this.middleButton = e.button === 1;
this.rightButton = e.button === 2;
this.buttons = e.buttons;
this.defaultPrevented = e.defaultPrevented;
this.target = e.target;
this.detail = e.detail || 1;
if (e.type === 'dblclick') {
this.detail = 2;
}
this.ctrlKey = e.ctrlKey;
this.shiftKey = e.shiftKey;
this.altKey = e.altKey;
this.metaKey = e.metaKey;
if (typeof e.pageX === 'number') {
this.posx = e.pageX;
this.posy = e.pageY;
}
else {
// Probably hit by MSGestureEvent
this.posx = e.clientX + this.target.ownerDocument.body.scrollLeft + this.target.ownerDocument.documentElement.scrollLeft;
this.posy = e.clientY + this.target.ownerDocument.body.scrollTop + this.target.ownerDocument.documentElement.scrollTop;
}
// Find the position of the iframe this code is executing in relative to the iframe where the event was captured.
const iframeOffsets = IframeUtils.getPositionOfChildWindowRelativeToAncestorWindow(targetWindow, e.view);
this.posx -= iframeOffsets.left;
this.posy -= iframeOffsets.top;
}
preventDefault() {
this.browserEvent.preventDefault();
}
stopPropagation() {
this.browserEvent.stopPropagation();
}
}
class StandardWheelEvent {
constructor(e, deltaX = 0, deltaY = 0) {
this.browserEvent = e || null;
// eslint-disable-next-line local/code-no-any-casts
this.target = e ? (e.target || e.targetNode || e.srcElement) : null;
this.deltaY = deltaY;
this.deltaX = deltaX;
let shouldFactorDPR = false;
if (isChrome) {
// Chrome version >= 123 contains the fix to factor devicePixelRatio into the wheel event.
// See https://chromium.googlesource.com/chromium/src.git/+/be51b448441ff0c9d1f17e0f25c4bf1ab3f11f61
const chromeVersionMatch = navigator.userAgent.match(/Chrome\/(\d+)/);
const chromeMajorVersion = chromeVersionMatch ? parseInt(chromeVersionMatch[1]) : 123;
shouldFactorDPR = chromeMajorVersion <= 122;
}
if (e) {
// Old (deprecated) wheel events
// eslint-disable-next-line local/code-no-any-casts
const e1 = e;
// eslint-disable-next-line local/code-no-any-casts
const e2 = e;
const devicePixelRatio = e.view?.devicePixelRatio || 1;
// vertical delta scroll
if (typeof e1.wheelDeltaY !== 'undefined') {
if (shouldFactorDPR) {
// Refs https://github.com/microsoft/vscode/issues/146403#issuecomment-1854538928
this.deltaY = e1.wheelDeltaY / (120 * devicePixelRatio);
}
else {
this.deltaY = e1.wheelDeltaY / 120;
}
}
else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {
this.deltaY = -e2.detail / 3;
}
else if (e.type === 'wheel') {
// Modern wheel event
// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
const ev = e;
if (ev.deltaMode === ev.DOM_DELTA_LINE) {
// the deltas are expressed in lines
if (isFirefox && !isMacintosh) {
this.deltaY = -e.deltaY / 3;
}
else {
this.deltaY = -e.deltaY;
}
}
else {
this.deltaY = -e.deltaY / 40;
}
}
// horizontal delta scroll
if (typeof e1.wheelDeltaX !== 'undefined') {
if (isSafari && isWindows) {
this.deltaX = -(e1.wheelDeltaX / 120);
}
else if (shouldFactorDPR) {
// Refs https://github.com/microsoft/vscode/issues/146403#issuecomment-1854538928
this.deltaX = e1.wheelDeltaX / (120 * devicePixelRatio);
}
else {
this.deltaX = e1.wheelDeltaX / 120;
}
}
else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {
this.deltaX = -e.detail / 3;
}
else if (e.type === 'wheel') {
// Modern wheel event
// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
const ev = e;
if (ev.deltaMode === ev.DOM_DELTA_LINE) {
// the deltas are expressed in lines
if (isFirefox && !isMacintosh) {
this.deltaX = -e.deltaX / 3;
}
else {
this.deltaX = -e.deltaX;
}
}
else {
this.deltaX = -e.deltaX / 40;
}
}
// Assume a vertical scroll if nothing else worked
if (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {
if (shouldFactorDPR) {
// Refs https://github.com/microsoft/vscode/issues/146403#issuecomment-1854538928
this.deltaY = e.wheelDelta / (120 * devicePixelRatio);
}
else {
this.deltaY = e.wheelDelta / 120;
}
}
}
}
preventDefault() {
this.browserEvent?.preventDefault();
}
stopPropagation() {
this.browserEvent?.stopPropagation();
}
}
export { StandardMouseEvent, StandardWheelEvent };
+222
View File
@@ -0,0 +1,222 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var inputLatency;
(function (inputLatency) {
const totalKeydownTime = { total: 0, min: Number.MAX_VALUE, max: 0 };
const totalInputTime = { ...totalKeydownTime };
const totalRenderTime = { ...totalKeydownTime };
const totalInputLatencyTime = { ...totalKeydownTime };
let measurementsCount = 0;
const state = {
keydown: 0 /* EventPhase.Before */,
input: 0 /* EventPhase.Before */,
render: 0 /* EventPhase.Before */,
};
/**
* Record the start of the keydown event.
*/
function onKeyDown() {
/** Direct Check C. See explanation in {@link recordIfFinished} */
recordIfFinished();
performance.mark('inputlatency/start');
performance.mark('keydown/start');
state.keydown = 1 /* EventPhase.InProgress */;
queueMicrotask(markKeyDownEnd);
}
inputLatency.onKeyDown = onKeyDown;
/**
* Mark the end of the keydown event.
*/
function markKeyDownEnd() {
if (state.keydown === 1 /* EventPhase.InProgress */) {
performance.mark('keydown/end');
state.keydown = 2 /* EventPhase.Finished */;
}
}
/**
* Record the start of the beforeinput event.
*/
function onBeforeInput() {
performance.mark('input/start');
state.input = 1 /* EventPhase.InProgress */;
/** Schedule Task A. See explanation in {@link recordIfFinished} */
scheduleRecordIfFinishedTask();
}
inputLatency.onBeforeInput = onBeforeInput;
/**
* Record the start of the input event.
*/
function onInput() {
if (state.input === 0 /* EventPhase.Before */) {
// it looks like we didn't receive a `beforeinput`
onBeforeInput();
}
queueMicrotask(markInputEnd);
}
inputLatency.onInput = onInput;
function markInputEnd() {
if (state.input === 1 /* EventPhase.InProgress */) {
performance.mark('input/end');
state.input = 2 /* EventPhase.Finished */;
}
}
/**
* Record the start of the keyup event.
*/
function onKeyUp() {
/** Direct Check D. See explanation in {@link recordIfFinished} */
recordIfFinished();
}
inputLatency.onKeyUp = onKeyUp;
/**
* Record the start of the selectionchange event.
*/
function onSelectionChange() {
/** Direct Check E. See explanation in {@link recordIfFinished} */
recordIfFinished();
}
inputLatency.onSelectionChange = onSelectionChange;
/**
* Record the start of the animation frame performing the rendering.
*/
function onRenderStart() {
// Render may be triggered during input, but we only measure the following animation frame
if (state.keydown === 2 /* EventPhase.Finished */ && state.input === 2 /* EventPhase.Finished */ && state.render === 0 /* EventPhase.Before */) {
// Only measure the first render after keyboard input
performance.mark('render/start');
state.render = 1 /* EventPhase.InProgress */;
queueMicrotask(markRenderEnd);
/** Schedule Task B. See explanation in {@link recordIfFinished} */
scheduleRecordIfFinishedTask();
}
}
inputLatency.onRenderStart = onRenderStart;
/**
* Mark the end of the animation frame performing the rendering.
*/
function markRenderEnd() {
if (state.render === 1 /* EventPhase.InProgress */) {
performance.mark('render/end');
state.render = 2 /* EventPhase.Finished */;
}
}
function scheduleRecordIfFinishedTask() {
// Here we can safely assume that the `setTimeout` will not be
// artificially delayed by 4ms because we schedule it from
// event handlers
setTimeout(recordIfFinished);
}
/**
* Record the input latency sample if input handling and rendering are finished.
*
* The challenge here is that we want to record the latency in such a way that it includes
* also the layout and painting work the browser does during the animation frame task.
*
* Simply scheduling a new task (via `setTimeout`) from the animation frame task would
* schedule the new task at the end of the task queue (after other code that uses `setTimeout`),
* so we need to use multiple strategies to make sure our task runs before others:
*
* We schedule tasks (A and B):
* - we schedule a task A (via a `setTimeout` call) when the input starts in `markInputStart`.
* If the animation frame task is scheduled quickly by the browser, then task A has a very good
* chance of being the very first task after the animation frame and thus will record the input latency.
* - however, if the animation frame task is scheduled a bit later, then task A might execute
* before the animation frame task. We therefore schedule another task B from `markRenderStart`.
*
* We do direct checks in browser event handlers (C, D, E):
* - if the browser has multiple keydown events queued up, they will be scheduled before the `setTimeout` tasks,
* so we do a direct check in the keydown event handler (C).
* - depending on timing, sometimes the animation frame is scheduled even before the `keyup` event, so we
* do a direct check there too (E).
* - the browser oftentimes emits a `selectionchange` event after an `input`, so we do a direct check there (D).
*/
function recordIfFinished() {
if (state.keydown === 2 /* EventPhase.Finished */ && state.input === 2 /* EventPhase.Finished */ && state.render === 2 /* EventPhase.Finished */) {
performance.mark('inputlatency/end');
performance.measure('keydown', 'keydown/start', 'keydown/end');
performance.measure('input', 'input/start', 'input/end');
performance.measure('render', 'render/start', 'render/end');
performance.measure('inputlatency', 'inputlatency/start', 'inputlatency/end');
addMeasure('keydown', totalKeydownTime);
addMeasure('input', totalInputTime);
addMeasure('render', totalRenderTime);
addMeasure('inputlatency', totalInputLatencyTime);
// console.info(
// `input latency=${performance.getEntriesByName('inputlatency')[0].duration.toFixed(1)} [` +
// `keydown=${performance.getEntriesByName('keydown')[0].duration.toFixed(1)}, ` +
// `input=${performance.getEntriesByName('input')[0].duration.toFixed(1)}, ` +
// `render=${performance.getEntriesByName('render')[0].duration.toFixed(1)}` +
// `]`
// );
measurementsCount++;
reset();
}
}
function addMeasure(entryName, cumulativeMeasurement) {
const duration = performance.getEntriesByName(entryName)[0].duration;
cumulativeMeasurement.total += duration;
cumulativeMeasurement.min = Math.min(cumulativeMeasurement.min, duration);
cumulativeMeasurement.max = Math.max(cumulativeMeasurement.max, duration);
}
/**
* Clear the current sample.
*/
function reset() {
performance.clearMarks('keydown/start');
performance.clearMarks('keydown/end');
performance.clearMarks('input/start');
performance.clearMarks('input/end');
performance.clearMarks('render/start');
performance.clearMarks('render/end');
performance.clearMarks('inputlatency/start');
performance.clearMarks('inputlatency/end');
performance.clearMeasures('keydown');
performance.clearMeasures('input');
performance.clearMeasures('render');
performance.clearMeasures('inputlatency');
state.keydown = 0 /* EventPhase.Before */;
state.input = 0 /* EventPhase.Before */;
state.render = 0 /* EventPhase.Before */;
}
/**
* Gets all input latency samples and clears the internal buffers to start recording a new set
* of samples.
*/
function getAndClearMeasurements() {
if (measurementsCount === 0) {
return undefined;
}
// Assemble the result
const result = {
keydown: cumulativeToFinalMeasurement(totalKeydownTime),
input: cumulativeToFinalMeasurement(totalInputTime),
render: cumulativeToFinalMeasurement(totalRenderTime),
total: cumulativeToFinalMeasurement(totalInputLatencyTime),
sampleCount: measurementsCount
};
// Clear the cumulative measurements
clearCumulativeMeasurement(totalKeydownTime);
clearCumulativeMeasurement(totalInputTime);
clearCumulativeMeasurement(totalRenderTime);
clearCumulativeMeasurement(totalInputLatencyTime);
measurementsCount = 0;
return result;
}
inputLatency.getAndClearMeasurements = getAndClearMeasurements;
function cumulativeToFinalMeasurement(cumulative) {
return {
average: cumulative.total / measurementsCount,
max: cumulative.max,
min: cumulative.min,
};
}
function clearCumulativeMeasurement(cumulative) {
cumulative.total = 0;
cumulative.min = Number.MAX_VALUE;
cumulative.max = 0;
}
})(inputLatency || (inputLatency = {}));
export { inputLatency };
+88
View File
@@ -0,0 +1,88 @@
import { getWindowId, onDidUnregisterWindow } from './dom.js';
import { Event, Emitter } from '../common/event.js';
import { markAsSingleton, Disposable } from '../common/lifecycle.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* See https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes
*/
class DevicePixelRatioMonitor extends Disposable {
constructor(targetWindow) {
super();
this._onDidChange = this._register(new Emitter());
this.onDidChange = this._onDidChange.event;
this._listener = () => this._handleChange(targetWindow, true);
this._mediaQueryList = null;
this._handleChange(targetWindow, false);
}
_handleChange(targetWindow, fireEvent) {
this._mediaQueryList?.removeEventListener('change', this._listener);
this._mediaQueryList = targetWindow.matchMedia(`(resolution: ${targetWindow.devicePixelRatio}dppx)`);
this._mediaQueryList.addEventListener('change', this._listener);
if (fireEvent) {
this._onDidChange.fire();
}
}
}
class PixelRatioMonitorImpl extends Disposable {
get value() {
return this._value;
}
constructor(targetWindow) {
super();
this._onDidChange = this._register(new Emitter());
this.onDidChange = this._onDidChange.event;
this._value = this._getPixelRatio(targetWindow);
const dprMonitor = this._register(new DevicePixelRatioMonitor(targetWindow));
this._register(dprMonitor.onDidChange(() => {
this._value = this._getPixelRatio(targetWindow);
this._onDidChange.fire(this._value);
}));
}
_getPixelRatio(targetWindow) {
const ctx = document.createElement('canvas').getContext('2d');
const dpr = targetWindow.devicePixelRatio || 1;
const bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
return dpr / bsr;
}
}
class PixelRatioMonitorFacade {
constructor() {
this.mapWindowIdToPixelRatioMonitor = new Map();
}
_getOrCreatePixelRatioMonitor(targetWindow) {
const targetWindowId = getWindowId(targetWindow);
let pixelRatioMonitor = this.mapWindowIdToPixelRatioMonitor.get(targetWindowId);
if (!pixelRatioMonitor) {
pixelRatioMonitor = markAsSingleton(new PixelRatioMonitorImpl(targetWindow));
this.mapWindowIdToPixelRatioMonitor.set(targetWindowId, pixelRatioMonitor);
markAsSingleton(Event.once(onDidUnregisterWindow)(({ vscodeWindowId }) => {
if (vscodeWindowId === targetWindowId) {
pixelRatioMonitor?.dispose();
this.mapWindowIdToPixelRatioMonitor.delete(targetWindowId);
}
}));
}
return pixelRatioMonitor;
}
getInstance(targetWindow) {
return this._getOrCreatePixelRatioMonitor(targetWindow);
}
}
/**
* Returns the pixel ratio.
*
* This is useful for rendering <canvas> elements at native screen resolution or for being used as
* a cache key when storing font measurements. Fonts might render differently depending on resolution
* and any measurements need to be discarded for example when a window is moved from a monitor to another.
*/
const PixelRatio = new PixelRatioMonitorFacade();
export { PixelRatio };
+270
View File
@@ -0,0 +1,270 @@
import { onDidRegisterWindow, addDisposableListener, scheduleAtNextAnimationFrame } from './dom.js';
import { mainWindow } from './window.js';
import { memoize } from '../common/decorators.js';
import { Event } from '../common/event.js';
import { Disposable, markAsSingleton, toDisposable } from '../common/lifecycle.js';
import { LinkedList } from '../common/linkedList.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var EventType;
(function (EventType) {
EventType.Tap = '-monaco-gesturetap';
EventType.Change = '-monaco-gesturechange';
EventType.Start = '-monaco-gesturestart';
EventType.End = '-monaco-gesturesend';
EventType.Contextmenu = '-monaco-gesturecontextmenu';
})(EventType || (EventType = {}));
class Gesture extends Disposable {
static { this.SCROLL_FRICTION = -5e-3; }
static { this.HOLD_DELAY = 700; }
static { this.CLEAR_TAP_COUNT_TIME = 400; } // ms
constructor() {
super();
this.dispatched = false;
this.targets = new LinkedList();
this.ignoreTargets = new LinkedList();
this.activeTouches = {};
this.handle = null;
this._lastSetTapCountTime = 0;
this._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposables }) => {
disposables.add(addDisposableListener(window.document, 'touchstart', (e) => this.onTouchStart(e), { passive: false }));
disposables.add(addDisposableListener(window.document, 'touchend', (e) => this.onTouchEnd(window, e)));
disposables.add(addDisposableListener(window.document, 'touchmove', (e) => this.onTouchMove(e), { passive: false }));
}, { window: mainWindow, disposables: this._store }));
}
static addTarget(element) {
if (!Gesture.isTouchDevice()) {
return Disposable.None;
}
if (!Gesture.INSTANCE) {
Gesture.INSTANCE = markAsSingleton(new Gesture());
}
const remove = Gesture.INSTANCE.targets.push(element);
return toDisposable(remove);
}
static ignoreTarget(element) {
if (!Gesture.isTouchDevice()) {
return Disposable.None;
}
if (!Gesture.INSTANCE) {
Gesture.INSTANCE = markAsSingleton(new Gesture());
}
const remove = Gesture.INSTANCE.ignoreTargets.push(element);
return toDisposable(remove);
}
static isTouchDevice() {
// `'ontouchstart' in window` always evaluates to true with typescript's modern typings. This causes `window` to be
// `never` later in `window.navigator`. That's why we need the explicit `window as Window` cast
return 'ontouchstart' in mainWindow || navigator.maxTouchPoints > 0;
}
dispose() {
if (this.handle) {
this.handle.dispose();
this.handle = null;
}
super.dispose();
}
onTouchStart(e) {
const timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.
if (this.handle) {
this.handle.dispose();
this.handle = null;
}
for (let i = 0, len = e.targetTouches.length; i < len; i++) {
const touch = e.targetTouches.item(i);
this.activeTouches[touch.identifier] = {
id: touch.identifier,
initialTarget: touch.target,
initialTimeStamp: timestamp,
initialPageX: touch.pageX,
initialPageY: touch.pageY,
rollingTimestamps: [timestamp],
rollingPageX: [touch.pageX],
rollingPageY: [touch.pageY]
};
const evt = this.newGestureEvent(EventType.Start, touch.target);
evt.pageX = touch.pageX;
evt.pageY = touch.pageY;
this.dispatchEvent(evt);
}
if (this.dispatched) {
e.preventDefault();
e.stopPropagation();
this.dispatched = false;
}
}
onTouchEnd(targetWindow, e) {
const timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.
const activeTouchCount = Object.keys(this.activeTouches).length;
for (let i = 0, len = e.changedTouches.length; i < len; i++) {
const touch = e.changedTouches.item(i);
if (!this.activeTouches.hasOwnProperty(String(touch.identifier))) {
console.warn('move of an UNKNOWN touch', touch);
continue;
}
const data = this.activeTouches[touch.identifier], holdTime = Date.now() - data.initialTimeStamp;
if (holdTime < Gesture.HOLD_DELAY
&& Math.abs(data.initialPageX - data.rollingPageX.at(-1)) < 30
&& Math.abs(data.initialPageY - data.rollingPageY.at(-1)) < 30) {
const evt = this.newGestureEvent(EventType.Tap, data.initialTarget);
evt.pageX = data.rollingPageX.at(-1);
evt.pageY = data.rollingPageY.at(-1);
this.dispatchEvent(evt);
}
else if (holdTime >= Gesture.HOLD_DELAY
&& Math.abs(data.initialPageX - data.rollingPageX.at(-1)) < 30
&& Math.abs(data.initialPageY - data.rollingPageY.at(-1)) < 30) {
const evt = this.newGestureEvent(EventType.Contextmenu, data.initialTarget);
evt.pageX = data.rollingPageX.at(-1);
evt.pageY = data.rollingPageY.at(-1);
this.dispatchEvent(evt);
}
else if (activeTouchCount === 1) {
const finalX = data.rollingPageX.at(-1);
const finalY = data.rollingPageY.at(-1);
const deltaT = data.rollingTimestamps.at(-1) - data.rollingTimestamps[0];
const deltaX = finalX - data.rollingPageX[0];
const deltaY = finalY - data.rollingPageY[0];
// We need to get all the dispatch targets on the start of the inertia event
const dispatchTo = [...this.targets].filter(t => data.initialTarget instanceof Node && t.contains(data.initialTarget));
this.inertia(targetWindow, dispatchTo, timestamp, // time now
Math.abs(deltaX) / deltaT, // speed
deltaX > 0 ? 1 : -1, // x direction
finalX, // x now
Math.abs(deltaY) / deltaT, // y speed
deltaY > 0 ? 1 : -1, // y direction
finalY // y now
);
}
this.dispatchEvent(this.newGestureEvent(EventType.End, data.initialTarget));
// forget about this touch
delete this.activeTouches[touch.identifier];
}
if (this.dispatched) {
e.preventDefault();
e.stopPropagation();
this.dispatched = false;
}
}
newGestureEvent(type, initialTarget) {
const event = document.createEvent('CustomEvent');
event.initEvent(type, false, true);
event.initialTarget = initialTarget;
event.tapCount = 0;
return event;
}
dispatchEvent(event) {
if (event.type === EventType.Tap) {
const currentTime = (new Date()).getTime();
let setTapCount = 0;
if (currentTime - this._lastSetTapCountTime > Gesture.CLEAR_TAP_COUNT_TIME) {
setTapCount = 1;
}
else {
setTapCount = 2;
}
this._lastSetTapCountTime = currentTime;
event.tapCount = setTapCount;
}
else if (event.type === EventType.Change || event.type === EventType.Contextmenu) {
// tap is canceled by scrolling or context menu
this._lastSetTapCountTime = 0;
}
if (event.initialTarget instanceof Node) {
for (const ignoreTarget of this.ignoreTargets) {
if (ignoreTarget.contains(event.initialTarget)) {
return;
}
}
const targets = [];
for (const target of this.targets) {
if (target.contains(event.initialTarget)) {
let depth = 0;
let now = event.initialTarget;
while (now && now !== target) {
depth++;
now = now.parentElement;
}
targets.push([depth, target]);
}
}
targets.sort((a, b) => a[0] - b[0]);
for (const [_, target] of targets) {
target.dispatchEvent(event);
this.dispatched = true;
}
}
}
inertia(targetWindow, dispatchTo, t1, vX, dirX, x, vY, dirY, y) {
this.handle = scheduleAtNextAnimationFrame(targetWindow, () => {
const now = Date.now();
// velocity: old speed + accel_over_time
const deltaT = now - t1;
let delta_pos_x = 0, delta_pos_y = 0;
let stopped = true;
vX += Gesture.SCROLL_FRICTION * deltaT;
vY += Gesture.SCROLL_FRICTION * deltaT;
if (vX > 0) {
stopped = false;
delta_pos_x = dirX * vX * deltaT;
}
if (vY > 0) {
stopped = false;
delta_pos_y = dirY * vY * deltaT;
}
// dispatch translation event
const evt = this.newGestureEvent(EventType.Change);
evt.translationX = delta_pos_x;
evt.translationY = delta_pos_y;
dispatchTo.forEach(d => d.dispatchEvent(evt));
if (!stopped) {
this.inertia(targetWindow, dispatchTo, now, vX, dirX, x + delta_pos_x, vY, dirY, y + delta_pos_y);
}
});
}
onTouchMove(e) {
const timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.
for (let i = 0, len = e.changedTouches.length; i < len; i++) {
const touch = e.changedTouches.item(i);
if (!this.activeTouches.hasOwnProperty(String(touch.identifier))) {
console.warn('end of an UNKNOWN touch', touch);
continue;
}
const data = this.activeTouches[touch.identifier];
const evt = this.newGestureEvent(EventType.Change, data.initialTarget);
evt.translationX = touch.pageX - data.rollingPageX.at(-1);
evt.translationY = touch.pageY - data.rollingPageY.at(-1);
evt.pageX = touch.pageX;
evt.pageY = touch.pageY;
this.dispatchEvent(evt);
// only keep a few data points, to average the final speed
if (data.rollingPageX.length > 3) {
data.rollingPageX.shift();
data.rollingPageY.shift();
data.rollingTimestamps.shift();
}
data.rollingPageX.push(touch.pageX);
data.rollingPageY.push(touch.pageY);
data.rollingTimestamps.push(timestamp);
}
if (this.dispatched) {
e.preventDefault();
e.stopPropagation();
this.dispatched = false;
}
}
}
__decorate([
memoize
], Gesture, "isTouchDevice", null);
export { EventType, Gesture };
@@ -0,0 +1,29 @@
import { onUnexpectedError } from '../common/errors.js';
import { getMonacoEnvironment } from './browser.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
function createTrustedTypesPolicy(policyName, policyOptions) {
const monacoEnvironment = getMonacoEnvironment();
if (monacoEnvironment?.createTrustedTypesPolicy) {
try {
return monacoEnvironment.createTrustedTypesPolicy(policyName, policyOptions);
}
catch (err) {
onUnexpectedError(err);
return undefined;
}
}
try {
// eslint-disable-next-line local/code-no-any-casts
return globalThis.trustedTypes?.createPolicy(policyName, policyOptions);
}
catch (err) {
onUnexpectedError(err);
return undefined;
}
}
export { createTrustedTypesPolicy };
@@ -0,0 +1,376 @@
import { isFirefox } from '../../browser.js';
import { DataTransfers } from '../../dnd.js';
import { addDisposableListener, EventType, EventHelper } from '../../dom.js';
import { Gesture, EventType as EventType$1 } from '../../touch.js';
import { getDefaultHoverDelegate } from '../hover/hoverDelegateFactory.js';
import { SelectBox } from '../selectBox/selectBox.js';
import { Action, ActionRunner, Separator } from '../../../common/actions.js';
import { Disposable } from '../../../common/lifecycle.js';
import { isMacintosh } from '../../../common/platform.js';
import { isUndefinedOrNull, assertType } from '../../../common/types.js';
import './actionbar.css';
import { localize } from '../../../../nls.js';
import { getBaseLayerHoverDelegate } from '../hover/hoverDelegate2.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class BaseActionViewItem extends Disposable {
get action() {
return this._action;
}
constructor(context, action, options = {}) {
super();
this.options = options;
this._context = context || this;
this._action = action;
if (action instanceof Action) {
this._register(action.onDidChange(event => {
if (!this.element) {
// we have not been rendered yet, so there
// is no point in updating the UI
return;
}
this.handleActionChangeEvent(event);
}));
}
}
handleActionChangeEvent(event) {
if (event.enabled !== undefined) {
this.updateEnabled();
}
if (event.checked !== undefined) {
this.updateChecked();
}
if (event.class !== undefined) {
this.updateClass();
}
if (event.label !== undefined) {
this.updateLabel();
this.updateTooltip();
}
if (event.tooltip !== undefined) {
this.updateTooltip();
}
}
get actionRunner() {
if (!this._actionRunner) {
this._actionRunner = this._register(new ActionRunner());
}
return this._actionRunner;
}
set actionRunner(actionRunner) {
this._actionRunner = actionRunner;
}
isEnabled() {
return this._action.enabled;
}
setActionContext(newContext) {
this._context = newContext;
}
render(container) {
const element = this.element = container;
this._register(Gesture.addTarget(container));
const enableDragging = this.options && this.options.draggable;
if (enableDragging) {
container.draggable = true;
if (isFirefox) {
// Firefox: requires to set a text data transfer to get going
this._register(addDisposableListener(container, EventType.DRAG_START, e => e.dataTransfer?.setData(DataTransfers.TEXT, this._action.label)));
}
}
this._register(addDisposableListener(element, EventType$1.Tap, e => this.onClick(e, true))); // Preserve focus on tap #125470
this._register(addDisposableListener(element, EventType.MOUSE_DOWN, e => {
if (!enableDragging) {
EventHelper.stop(e, true); // do not run when dragging is on because that would disable it
}
if (this._action.enabled && e.button === 0) {
element.classList.add('active');
}
}));
if (isMacintosh) {
// macOS: allow to trigger the button when holding Ctrl+key and pressing the
// main mouse button. This is for scenarios where e.g. some interaction forces
// the Ctrl+key to be pressed and hold but the user still wants to interact
// with the actions (for example quick access in quick navigation mode).
this._register(addDisposableListener(element, EventType.CONTEXT_MENU, e => {
if (e.button === 0 && e.ctrlKey === true) {
this.onClick(e);
}
}));
}
this._register(addDisposableListener(element, EventType.CLICK, e => {
EventHelper.stop(e, true);
// menus do not use the click event
if (!(this.options && this.options.isMenu)) {
this.onClick(e);
}
}));
this._register(addDisposableListener(element, EventType.DBLCLICK, e => {
EventHelper.stop(e, true);
}));
[EventType.MOUSE_UP, EventType.MOUSE_OUT].forEach(event => {
this._register(addDisposableListener(element, event, e => {
EventHelper.stop(e);
element.classList.remove('active');
}));
});
}
onClick(event, preserveFocus = false) {
EventHelper.stop(event, true);
const context = isUndefinedOrNull(this._context) ? this.options?.useEventAsContext ? event : { preserveFocus } : this._context;
this.actionRunner.run(this._action, context);
}
// Only set the tabIndex on the element once it is about to get focused
// That way this element wont be a tab stop when it is not needed #106441
focus() {
if (this.element) {
this.element.tabIndex = 0;
this.element.focus();
this.element.classList.add('focused');
}
}
blur() {
if (this.element) {
this.element.blur();
this.element.tabIndex = -1;
this.element.classList.remove('focused');
}
}
setFocusable(focusable) {
if (this.element) {
this.element.tabIndex = focusable ? 0 : -1;
}
}
get trapsArrowNavigation() {
return false;
}
updateEnabled() {
// implement in subclass
}
updateLabel() {
// implement in subclass
}
getClass() {
return this.action.class;
}
getTooltip() {
return this.action.tooltip;
}
getHoverContents() {
return this.getTooltip();
}
updateTooltip() {
if (!this.element) {
return;
}
const title = this.getHoverContents() ?? '';
this.updateAriaLabel();
if (!this.customHover && title !== '') {
const hoverDelegate = this.options.hoverDelegate ?? getDefaultHoverDelegate('element');
this.customHover = this._store.add(getBaseLayerHoverDelegate().setupManagedHover(hoverDelegate, this.element, title));
}
else if (this.customHover) {
this.customHover.update(title);
}
}
updateAriaLabel() {
if (this.element) {
const title = this.getTooltip() ?? '';
this.element.setAttribute('aria-label', title);
}
}
updateClass() {
// implement in subclass
}
updateChecked() {
// implement in subclass
}
dispose() {
if (this.element) {
this.element.remove();
this.element = undefined;
}
this._context = undefined;
super.dispose();
}
}
class ActionViewItem extends BaseActionViewItem {
constructor(context, action, options) {
options = {
...options,
icon: options.icon !== undefined ? options.icon : false,
label: options.label !== undefined ? options.label : true,
};
super(context, action, options);
this.options = options;
this.cssClass = '';
}
render(container) {
super.render(container);
assertType(this.element);
const label = document.createElement('a');
label.classList.add('action-label');
label.setAttribute('role', this.getDefaultAriaRole());
this.label = label;
this.element.appendChild(label);
if (this.options.label && this.options.keybinding && !this.options.keybindingNotRenderedWithLabel) {
const kbLabel = document.createElement('span');
kbLabel.classList.add('keybinding');
kbLabel.textContent = this.options.keybinding;
this.element.appendChild(kbLabel);
}
this.updateClass();
this.updateLabel();
this.updateTooltip();
this.updateEnabled();
this.updateChecked();
}
getDefaultAriaRole() {
if (this._action.id === Separator.ID) {
return 'presentation'; // A separator is a presentation item
}
else {
if (this.options.isMenu) {
return 'menuitem';
}
else if (this.options.isTabList) {
return 'tab';
}
else {
return 'button';
}
}
}
// Only set the tabIndex on the element once it is about to get focused
// That way this element wont be a tab stop when it is not needed #106441
focus() {
if (this.label) {
this.label.tabIndex = 0;
this.label.focus();
}
}
blur() {
if (this.label) {
this.label.tabIndex = -1;
}
}
setFocusable(focusable) {
if (this.label) {
this.label.tabIndex = focusable ? 0 : -1;
}
}
updateLabel() {
if (this.options.label && this.label) {
this.label.textContent = this.action.label;
}
}
getTooltip() {
let title = null;
if (this.action.tooltip) {
title = this.action.tooltip;
}
else if (this.action.label) {
title = this.action.label;
if (this.options.keybinding) {
title = localize(0, "{0} ({1})", title, this.options.keybinding);
}
}
return title ?? undefined;
}
updateClass() {
if (this.cssClass && this.label) {
this.label.classList.remove(...this.cssClass.split(' '));
}
if (this.options.icon) {
this.cssClass = this.getClass();
if (this.label) {
this.label.classList.add('codicon');
if (this.cssClass) {
this.label.classList.add(...this.cssClass.split(' '));
}
}
this.updateEnabled();
}
else {
this.label?.classList.remove('codicon');
}
}
updateEnabled() {
if (this.action.enabled) {
if (this.label) {
this.label.removeAttribute('aria-disabled');
this.label.classList.remove('disabled');
}
this.element?.classList.remove('disabled');
}
else {
if (this.label) {
this.label.setAttribute('aria-disabled', 'true');
this.label.classList.add('disabled');
}
this.element?.classList.add('disabled');
}
}
updateAriaLabel() {
if (this.label) {
const title = this.getTooltip() ?? '';
this.label.setAttribute('aria-label', title);
}
}
updateChecked() {
if (this.label) {
if (this.action.checked !== undefined) {
this.label.classList.toggle('checked', this.action.checked);
if (this.options.isTabList) {
this.label.setAttribute('aria-selected', this.action.checked ? 'true' : 'false');
}
else {
this.label.setAttribute('aria-checked', this.action.checked ? 'true' : 'false');
this.label.setAttribute('role', 'checkbox');
}
}
else {
this.label.classList.remove('checked');
this.label.removeAttribute(this.options.isTabList ? 'aria-selected' : 'aria-checked');
this.label.setAttribute('role', this.getDefaultAriaRole());
}
}
}
}
class SelectActionViewItem extends BaseActionViewItem {
constructor(ctx, action, options, selected, contextViewProvider, styles, selectBoxOptions) {
super(ctx, action);
this.selectBox = new SelectBox(options, selected, contextViewProvider, styles, selectBoxOptions);
this.selectBox.setFocusable(false);
this._register(this.selectBox);
this.registerListeners();
}
select(index) {
this.selectBox.select(index);
}
registerListeners() {
this._register(this.selectBox.onDidSelect(e => this.runAction(e.selected, e.index)));
}
runAction(option, index) {
this.actionRunner.run(this._action, this.getActionContext(option, index));
}
getActionContext(option, index) {
return option;
}
setFocusable(focusable) {
this.selectBox.setFocusable(focusable);
}
focus() {
this.selectBox?.focus();
}
blur() {
this.selectBox?.blur();
}
render(container) {
this.selectBox.render(container);
}
}
export { ActionViewItem, BaseActionViewItem, SelectActionViewItem };
@@ -0,0 +1,124 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-action-bar {
white-space: nowrap;
height: 100%;
}
.monaco-action-bar .actions-container {
display: flex;
margin: 0 auto;
padding: 0;
height: 100%;
width: 100%;
align-items: center;
}
.monaco-action-bar.vertical .actions-container {
display: inline-block;
}
.monaco-action-bar .action-item {
display: block;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */
}
.monaco-action-bar .action-item.disabled {
cursor: default;
}
.monaco-action-bar .action-item .icon,
.monaco-action-bar .action-item .codicon {
display: block;
}
.monaco-action-bar .action-item .codicon {
display: flex;
align-items: center;
width: 16px;
height: 16px;
}
.monaco-action-bar .action-label {
display: flex;
font-size: 11px;
padding: 3px;
border-radius: 5px;
}
.monaco-action-bar .action-item.disabled .action-label:not(.icon) ,
.monaco-action-bar .action-item.disabled .action-label:not(.icon)::before,
.monaco-action-bar .action-item.disabled .action-label:not(.icon):hover {
color: var(--vscode-disabledForeground);
}
/* Unable to change color of SVGs, hence opacity is used */
.monaco-action-bar .action-item.disabled .action-label.icon ,
.monaco-action-bar .action-item.disabled .action-label.icon::before,
.monaco-action-bar .action-item.disabled .action-label.icon:hover {
opacity: 0.6;
}
/* Vertical actions */
.monaco-action-bar.vertical {
text-align: left;
}
.monaco-action-bar.vertical .action-item {
display: block;
}
.monaco-action-bar.vertical .action-label.separator {
display: block;
border-bottom: 1px solid var(--vscode-disabledForeground);
padding-top: 1px;
margin-left: .8em;
margin-right: .8em;
}
.monaco-action-bar .action-item .action-label.separator {
width: 1px;
height: 16px;
margin: 5px 4px !important;
cursor: default;
min-width: 1px;
padding: 0;
background-color: var(--vscode-disabledForeground);
}
.secondary-actions .monaco-action-bar .action-label {
margin-left: 6px;
}
/* Action Items */
.monaco-action-bar .action-item.select-container {
overflow: hidden; /* somehow the dropdown overflows its container, we prevent it here to not push */
flex: 1;
max-width: 170px;
min-width: 60px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
}
.monaco-action-bar .action-item.action-dropdown-item {
display: flex;
}
.monaco-action-bar .action-item.action-dropdown-item > .action-dropdown-item-separator {
display: flex;
align-items: center;
cursor: default;
}
.monaco-action-bar .action-item.action-dropdown-item > .action-dropdown-item-separator > div {
width: 1px;
}
@@ -0,0 +1,462 @@
import { addDisposableListener, EventType, trackFocus, getActiveElement, isAncestor, isHTMLElement, EventHelper, clearNode } from '../../dom.js';
import { StandardKeyboardEvent } from '../../keyboardEvent.js';
import { BaseActionViewItem, ActionViewItem } from './actionViewItems.js';
import { createInstantHoverDelegate } from '../hover/hoverDelegateFactory.js';
import { ActionRunner, Separator } from '../../../common/actions.js';
import { Emitter } from '../../../common/event.js';
import { Disposable, DisposableStore, DisposableMap, dispose } from '../../../common/lifecycle.js';
import { isNumber, isFunction } from '../../../common/types.js';
import './actionbar.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class ActionBar extends Disposable {
get onDidBlur() { return this._onDidBlur.event; }
get onDidCancel() { return this._onDidCancel.event; }
get onDidRun() { return this._onDidRun.event; }
get onWillRun() { return this._onWillRun.event; }
constructor(container, options = {}) {
super();
this._actionRunnerDisposables = this._register(new DisposableStore());
this.viewItemDisposables = this._register(new DisposableMap());
// Trigger Key Tracking
this.triggerKeyDown = false;
this.focusable = true;
this._onDidBlur = this._register(new Emitter());
this._onDidCancel = this._register(new Emitter({ onWillAddFirstListener: () => this.cancelHasListener = true }));
this.cancelHasListener = false;
this._onDidRun = this._register(new Emitter());
this._onWillRun = this._register(new Emitter());
this.options = options;
this._context = options.context ?? null;
this._orientation = this.options.orientation ?? 0 /* ActionsOrientation.HORIZONTAL */;
this._triggerKeys = {
keyDown: this.options.triggerKeys?.keyDown ?? false,
keys: this.options.triggerKeys?.keys ?? [3 /* KeyCode.Enter */, 10 /* KeyCode.Space */]
};
this._hoverDelegate = options.hoverDelegate ?? this._register(createInstantHoverDelegate());
if (this.options.actionRunner) {
this._actionRunner = this.options.actionRunner;
}
else {
this._actionRunner = new ActionRunner();
this._actionRunnerDisposables.add(this._actionRunner);
}
this._actionRunnerDisposables.add(this._actionRunner.onDidRun(e => this._onDidRun.fire(e)));
this._actionRunnerDisposables.add(this._actionRunner.onWillRun(e => this._onWillRun.fire(e)));
this.viewItems = [];
this.focusedItem = undefined;
this.domNode = document.createElement('div');
this.domNode.className = 'monaco-action-bar';
let previousKeys;
let nextKeys;
switch (this._orientation) {
case 0 /* ActionsOrientation.HORIZONTAL */:
previousKeys = [15 /* KeyCode.LeftArrow */];
nextKeys = [17 /* KeyCode.RightArrow */];
break;
case 1 /* ActionsOrientation.VERTICAL */:
previousKeys = [16 /* KeyCode.UpArrow */];
nextKeys = [18 /* KeyCode.DownArrow */];
this.domNode.className += ' vertical';
break;
}
this._register(addDisposableListener(this.domNode, EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
let eventHandled = true;
const focusedItem = typeof this.focusedItem === 'number' ? this.viewItems[this.focusedItem] : undefined;
if (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) {
eventHandled = this.focusPrevious();
}
else if (nextKeys && (event.equals(nextKeys[0]) || event.equals(nextKeys[1]))) {
eventHandled = this.focusNext();
}
else if (event.equals(9 /* KeyCode.Escape */) && this.cancelHasListener) {
this._onDidCancel.fire();
}
else if (event.equals(14 /* KeyCode.Home */)) {
eventHandled = this.focusFirst();
}
else if (event.equals(13 /* KeyCode.End */)) {
eventHandled = this.focusLast();
}
else if (event.equals(2 /* KeyCode.Tab */) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) {
// Tab, so forcibly focus next #219199
eventHandled = this.focusNext(undefined, true);
}
else if (this.isTriggerKeyEvent(event)) {
// Staying out of the else branch even if not triggered
if (this._triggerKeys.keyDown) {
this.doTrigger(event);
}
else {
this.triggerKeyDown = true;
}
}
else {
eventHandled = false;
}
if (eventHandled) {
event.preventDefault();
event.stopPropagation();
}
}));
this._register(addDisposableListener(this.domNode, EventType.KEY_UP, e => {
const event = new StandardKeyboardEvent(e);
// Run action on Enter/Space
if (this.isTriggerKeyEvent(event)) {
if (!this._triggerKeys.keyDown && this.triggerKeyDown) {
this.triggerKeyDown = false;
this.doTrigger(event);
}
event.preventDefault();
event.stopPropagation();
}
// Recompute focused item
else if (event.equals(2 /* KeyCode.Tab */) || event.equals(1024 /* KeyMod.Shift */ | 2 /* KeyCode.Tab */) || event.equals(16 /* KeyCode.UpArrow */) || event.equals(18 /* KeyCode.DownArrow */) || event.equals(15 /* KeyCode.LeftArrow */) || event.equals(17 /* KeyCode.RightArrow */)) {
this.updateFocusedItem();
}
}));
this.focusTracker = this._register(trackFocus(this.domNode));
this._register(this.focusTracker.onDidBlur(() => {
if (getActiveElement() === this.domNode || !isAncestor(getActiveElement(), this.domNode)) {
this._onDidBlur.fire();
this.previouslyFocusedItem = this.focusedItem;
this.focusedItem = undefined;
this.triggerKeyDown = false;
}
}));
this._register(this.focusTracker.onDidFocus(() => this.updateFocusedItem()));
this.actionsList = document.createElement('ul');
this.actionsList.className = 'actions-container';
if (this.options.highlightToggledItems) {
this.actionsList.classList.add('highlight-toggled');
}
this.actionsList.setAttribute('role', this.options.ariaRole || 'toolbar');
if (this.options.ariaLabel) {
this.actionsList.setAttribute('aria-label', this.options.ariaLabel);
}
this.domNode.appendChild(this.actionsList);
container.appendChild(this.domNode);
}
refreshRole() {
if (this.length() >= 1) {
this.actionsList.setAttribute('role', this.options.ariaRole || 'toolbar');
}
else {
this.actionsList.setAttribute('role', 'presentation');
}
}
// Some action bars should not be focusable at times
// When an action bar is not focusable make sure to make all the elements inside it not focusable
// When an action bar is focusable again, make sure the first item can be focused
setFocusable(focusable) {
this.focusable = focusable;
if (this.focusable) {
const firstEnabled = this.viewItems.find(vi => vi instanceof BaseActionViewItem && vi.isEnabled());
if (firstEnabled instanceof BaseActionViewItem) {
firstEnabled.setFocusable(true);
}
}
else {
this.viewItems.forEach(vi => {
if (vi instanceof BaseActionViewItem) {
vi.setFocusable(false);
}
});
}
}
isTriggerKeyEvent(event) {
let ret = false;
this._triggerKeys.keys.forEach(keyCode => {
ret = ret || event.equals(keyCode);
});
return ret;
}
updateFocusedItem() {
for (let i = 0; i < this.actionsList.children.length; i++) {
const elem = this.actionsList.children[i];
if (isAncestor(getActiveElement(), elem)) {
this.focusedItem = i;
this.viewItems[this.focusedItem]?.showHover?.();
break;
}
}
}
get context() {
return this._context;
}
set context(context) {
this._context = context;
this.viewItems.forEach(i => i.setActionContext(context));
}
get actionRunner() {
return this._actionRunner;
}
set actionRunner(actionRunner) {
this._actionRunner = actionRunner;
// when setting a new `IActionRunner` make sure to dispose old listeners and
// start to forward events from the new listener
this._actionRunnerDisposables.clear();
this._actionRunnerDisposables.add(this._actionRunner.onDidRun(e => this._onDidRun.fire(e)));
this._actionRunnerDisposables.add(this._actionRunner.onWillRun(e => this._onWillRun.fire(e)));
this.viewItems.forEach(item => item.actionRunner = actionRunner);
}
getContainer() {
return this.domNode;
}
getAction(indexOrElement) {
// by index
if (typeof indexOrElement === 'number') {
return this.viewItems[indexOrElement]?.action;
}
// by element
if (isHTMLElement(indexOrElement)) {
while (indexOrElement.parentElement !== this.actionsList) {
if (!indexOrElement.parentElement) {
return undefined;
}
indexOrElement = indexOrElement.parentElement;
}
for (let i = 0; i < this.actionsList.childNodes.length; i++) {
if (this.actionsList.childNodes[i] === indexOrElement) {
return this.viewItems[i].action;
}
}
}
return undefined;
}
push(arg, options = {}) {
const actions = Array.isArray(arg) ? arg : [arg];
let index = isNumber(options.index) ? options.index : null;
actions.forEach((action) => {
const actionViewItemElement = document.createElement('li');
actionViewItemElement.className = 'action-item';
actionViewItemElement.setAttribute('role', 'presentation');
let item;
const viewItemOptions = { hoverDelegate: this._hoverDelegate, ...options, isTabList: this.options.ariaRole === 'tablist' };
if (this.options.actionViewItemProvider) {
item = this.options.actionViewItemProvider(action, viewItemOptions);
}
if (!item) {
item = new ActionViewItem(this.context, action, viewItemOptions);
}
// Prevent native context menu on actions
if (!this.options.allowContextMenu) {
this.viewItemDisposables.set(item, addDisposableListener(actionViewItemElement, EventType.CONTEXT_MENU, (e) => {
EventHelper.stop(e, true);
}));
}
item.actionRunner = this._actionRunner;
item.setActionContext(this.context);
item.render(actionViewItemElement);
if (index === null || index < 0 || index >= this.actionsList.children.length) {
this.actionsList.appendChild(actionViewItemElement);
this.viewItems.push(item);
}
else {
this.actionsList.insertBefore(actionViewItemElement, this.actionsList.children[index]);
this.viewItems.splice(index, 0, item);
index++;
}
});
// We need to allow for the first enabled item to be focused on using tab navigation #106441
if (this.focusable) {
let didFocus = false;
for (const item of this.viewItems) {
if (!(item instanceof BaseActionViewItem)) {
continue;
}
let focus;
if (didFocus) {
focus = false; // already focused an item
}
else if (item.action.id === Separator.ID) {
focus = false; // never focus a separator
}
else if (!item.isEnabled() && this.options.focusOnlyEnabledItems) {
focus = false; // never focus a disabled item
}
else {
focus = true;
}
if (focus) {
item.setFocusable(true);
didFocus = true;
}
else {
item.setFocusable(false);
}
}
}
if (typeof this.focusedItem === 'number') {
// After a clear actions might be re-added to simply toggle some actions. We should preserve focus #97128
this.focus(this.focusedItem);
}
this.refreshRole();
}
getWidth(index) {
if (index >= 0 && index < this.actionsList.children.length) {
const item = this.actionsList.children.item(index);
if (item) {
return item.clientWidth;
}
}
return 0;
}
pull(index) {
if (index >= 0 && index < this.viewItems.length) {
this.actionsList.childNodes[index].remove();
this.viewItemDisposables.deleteAndDispose(this.viewItems[index]);
dispose(this.viewItems.splice(index, 1));
this.refreshRole();
}
}
clear() {
if (this.isEmpty()) {
return;
}
this.viewItems = dispose(this.viewItems);
this.viewItemDisposables.clearAndDisposeAll();
clearNode(this.actionsList);
this.refreshRole();
}
length() {
return this.viewItems.length;
}
isEmpty() {
return this.viewItems.length === 0;
}
focus(arg) {
let selectFirst = false;
let index = undefined;
if (arg === undefined) {
selectFirst = true;
}
else if (typeof arg === 'number') {
index = arg;
}
else if (typeof arg === 'boolean') {
selectFirst = arg;
}
if (selectFirst && typeof this.focusedItem === 'undefined') {
const firstEnabled = this.viewItems.findIndex(item => item.isEnabled());
// Focus the first enabled item
this.focusedItem = firstEnabled === -1 ? undefined : firstEnabled;
this.updateFocus(undefined, undefined, true);
}
else {
if (index !== undefined) {
this.focusedItem = index;
}
this.updateFocus(undefined, undefined, true);
}
}
focusFirst() {
this.focusedItem = this.length() - 1;
return this.focusNext(true);
}
focusLast() {
this.focusedItem = 0;
return this.focusPrevious(true);
}
focusNext(forceLoop, forceFocus) {
if (typeof this.focusedItem === 'undefined') {
this.focusedItem = this.viewItems.length - 1;
}
else if (this.viewItems.length <= 1) {
return false;
}
const startIndex = this.focusedItem;
let item;
do {
if (!forceLoop && this.options.preventLoopNavigation && this.focusedItem + 1 >= this.viewItems.length) {
this.focusedItem = startIndex;
return false;
}
this.focusedItem = (this.focusedItem + 1) % this.viewItems.length;
item = this.viewItems[this.focusedItem];
} while (this.focusedItem !== startIndex && ((this.options.focusOnlyEnabledItems && !item.isEnabled()) || item.action.id === Separator.ID));
this.updateFocus(undefined, undefined, forceFocus);
return true;
}
focusPrevious(forceLoop) {
if (typeof this.focusedItem === 'undefined') {
this.focusedItem = 0;
}
else if (this.viewItems.length <= 1) {
return false;
}
const startIndex = this.focusedItem;
let item;
do {
this.focusedItem = this.focusedItem - 1;
if (this.focusedItem < 0) {
if (!forceLoop && this.options.preventLoopNavigation) {
this.focusedItem = startIndex;
return false;
}
this.focusedItem = this.viewItems.length - 1;
}
item = this.viewItems[this.focusedItem];
} while (this.focusedItem !== startIndex && ((this.options.focusOnlyEnabledItems && !item.isEnabled()) || item.action.id === Separator.ID));
this.updateFocus(true);
return true;
}
updateFocus(fromRight, preventScroll, forceFocus = false) {
if (typeof this.focusedItem === 'undefined') {
this.actionsList.focus({ preventScroll });
}
if (this.previouslyFocusedItem !== undefined && this.previouslyFocusedItem !== this.focusedItem) {
this.viewItems[this.previouslyFocusedItem]?.blur();
}
const actionViewItem = this.focusedItem !== undefined ? this.viewItems[this.focusedItem] : undefined;
if (actionViewItem) {
let focusItem = true;
if (!isFunction(actionViewItem.focus)) {
focusItem = false;
}
if (this.options.focusOnlyEnabledItems && isFunction(actionViewItem.isEnabled) && !actionViewItem.isEnabled()) {
focusItem = false;
}
if (actionViewItem.action.id === Separator.ID) {
focusItem = false;
}
if (!focusItem) {
this.actionsList.focus({ preventScroll });
this.previouslyFocusedItem = undefined;
}
else if (forceFocus || this.previouslyFocusedItem !== this.focusedItem) {
actionViewItem.focus(fromRight);
this.previouslyFocusedItem = this.focusedItem;
}
if (focusItem) {
actionViewItem.showHover?.();
}
}
}
doTrigger(event) {
if (typeof this.focusedItem === 'undefined') {
return; //nothing to focus
}
// trigger action
const actionViewItem = this.viewItems[this.focusedItem];
if (actionViewItem instanceof BaseActionViewItem) {
const context = (actionViewItem._context === null || actionViewItem._context === undefined) ? event : actionViewItem._context;
this.run(actionViewItem._action, context);
}
}
async run(action, context) {
await this._actionRunner.run(action, context);
}
dispose() {
this._context = undefined;
this.viewItems = dispose(this.viewItems);
this.getContainer().remove();
super.dispose();
}
}
export { ActionBar };
@@ -0,0 +1,9 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-aria-container {
position: absolute; /* try to hide from window but not from screen readers */
left:-999em;
}
@@ -0,0 +1,84 @@
import { clearNode } from '../../dom.js';
import './aria.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// Use a max length since we are inserting the whole msg in the DOM and that can cause browsers to freeze for long messages #94233
const MAX_MESSAGE_LENGTH = 20000;
let ariaContainer;
let alertContainer;
let alertContainer2;
let statusContainer;
let statusContainer2;
function setARIAContainer(parent) {
ariaContainer = document.createElement('div');
ariaContainer.className = 'monaco-aria-container';
const createAlertContainer = () => {
const element = document.createElement('div');
element.className = 'monaco-alert';
element.setAttribute('role', 'alert');
element.setAttribute('aria-atomic', 'true');
ariaContainer.appendChild(element);
return element;
};
alertContainer = createAlertContainer();
alertContainer2 = createAlertContainer();
const createStatusContainer = () => {
const element = document.createElement('div');
element.className = 'monaco-status';
element.setAttribute('aria-live', 'polite');
element.setAttribute('aria-atomic', 'true');
ariaContainer.appendChild(element);
return element;
};
statusContainer = createStatusContainer();
statusContainer2 = createStatusContainer();
parent.appendChild(ariaContainer);
}
/**
* Given the provided message, will make sure that it is read as alert to screen readers.
*/
function alert(msg) {
if (!ariaContainer) {
return;
}
// Use alternate containers such that duplicated messages get read out by screen readers #99466
if (alertContainer.textContent !== msg) {
clearNode(alertContainer2);
insertMessage(alertContainer, msg);
}
else {
clearNode(alertContainer);
insertMessage(alertContainer2, msg);
}
}
/**
* Given the provided message, will make sure that it is read as status to screen readers.
*/
function status(msg) {
if (!ariaContainer) {
return;
}
if (statusContainer.textContent !== msg) {
clearNode(statusContainer2);
insertMessage(statusContainer, msg);
}
else {
clearNode(statusContainer);
insertMessage(statusContainer2, msg);
}
}
function insertMessage(target, msg) {
clearNode(target);
if (msg.length > MAX_MESSAGE_LENGTH) {
msg = msg.substr(0, MAX_MESSAGE_LENGTH);
}
target.textContent = msg;
// See https://www.paciellogroup.com/blog/2012/06/html5-accessibility-chops-aria-rolealert-browser-support/
target.style.visibility = 'hidden';
target.style.visibility = 'visible';
}
export { alert, setARIAContainer, status };
@@ -0,0 +1,174 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-text-button {
box-sizing: border-box;
display: flex;
width: 100%;
padding: 4px;
border-radius: 2px;
text-align: center;
cursor: pointer;
justify-content: center;
align-items: center;
border: 1px solid var(--vscode-button-border, transparent);
line-height: 18px;
}
.monaco-text-button:focus {
outline-offset: 2px !important;
}
.monaco-text-button:hover {
text-decoration: none !important;
}
.monaco-button.disabled:focus,
.monaco-button.disabled {
opacity: 0.4 !important;
cursor: default;
}
.monaco-text-button .codicon {
margin: 0 0.2em;
color: inherit !important;
}
.monaco-text-button.monaco-text-button-with-short-label {
flex-direction: row;
flex-wrap: wrap;
padding: 0 4px;
overflow: hidden;
height: 28px;
}
.monaco-text-button.monaco-text-button-with-short-label > .monaco-button-label {
flex-basis: 100%;
}
.monaco-text-button.monaco-text-button-with-short-label > .monaco-button-label-short {
flex-grow: 1;
width: 0;
overflow: hidden;
}
.monaco-text-button.monaco-text-button-with-short-label > .monaco-button-label,
.monaco-text-button.monaco-text-button-with-short-label > .monaco-button-label-short {
display: flex;
justify-content: center;
align-items: center;
font-weight: normal;
font-style: inherit;
padding: 4px 0;
}
.monaco-button-dropdown {
display: flex;
cursor: pointer;
}
.monaco-button-dropdown.disabled {
cursor: default;
}
.monaco-button-dropdown > .monaco-button:focus {
outline-offset: -1px !important;
}
.monaco-button-dropdown.disabled > .monaco-button.disabled,
.monaco-button-dropdown.disabled > .monaco-button.disabled:focus,
.monaco-button-dropdown.disabled > .monaco-button-dropdown-separator {
opacity: 0.4 !important;
}
.monaco-button-dropdown > .monaco-button.monaco-text-button {
border-right-width: 0 !important;
}
.monaco-button-dropdown .monaco-button-dropdown-separator {
padding: 4px 0;
cursor: default;
}
.monaco-button-dropdown .monaco-button-dropdown-separator > div {
height: 100%;
width: 1px;
}
.monaco-button-dropdown > .monaco-button.monaco-dropdown-button {
border: 1px solid var(--vscode-button-border, transparent);
border-left-width: 0 !important;
border-radius: 0 2px 2px 0;
display: flex;
align-items: center;
}
.monaco-button-dropdown > .monaco-button.monaco-text-button {
border-radius: 2px 0 0 2px;
}
.monaco-description-button {
display: flex;
flex-direction: column;
align-items: center;
margin: 4px 5px; /* allows button focus outline to be visible */
}
.monaco-description-button .monaco-button-description {
font-style: italic;
font-size: 11px;
padding: 4px 20px;
}
.monaco-description-button .monaco-button-label,
.monaco-description-button .monaco-button-description {
display: flex;
justify-content: center;
align-items: center;
}
.monaco-description-button .monaco-button-label > .codicon,
.monaco-description-button .monaco-button-description > .codicon {
margin: 0 0.2em;
color: inherit !important;
}
/* default color styles - based on CSS variables */
.monaco-button.default-colors,
.monaco-button-dropdown.default-colors > .monaco-button{
color: var(--vscode-button-foreground);
background-color: var(--vscode-button-background);
}
.monaco-button.default-colors:hover,
.monaco-button-dropdown.default-colors > .monaco-button:hover {
background-color: var(--vscode-button-hoverBackground);
}
.monaco-button.default-colors.secondary,
.monaco-button-dropdown.default-colors > .monaco-button.secondary {
color: var(--vscode-button-secondaryForeground);
background-color: var(--vscode-button-secondaryBackground);
}
.monaco-button.default-colors.secondary:hover,
.monaco-button-dropdown.default-colors > .monaco-button.secondary:hover {
background-color: var(--vscode-button-secondaryHoverBackground);
}
.monaco-button-dropdown.default-colors .monaco-button-dropdown-separator {
background-color: var(--vscode-button-background);
border-top: 1px solid var(--vscode-button-border);
border-bottom: 1px solid var(--vscode-button-border);
}
.monaco-button-dropdown.default-colors .monaco-button.secondary + .monaco-button-dropdown-separator {
background-color: var(--vscode-button-secondaryBackground);
}
.monaco-button-dropdown.default-colors .monaco-button-dropdown-separator > div {
background-color: var(--vscode-button-separator);
}
@@ -0,0 +1,226 @@
import { EventType, addDisposableListener, EventHelper, trackFocus, reset } from '../../dom.js';
import { StandardKeyboardEvent } from '../../keyboardEvent.js';
import { renderMarkdown, renderAsPlaintext } from '../../markdownRenderer.js';
import { Gesture, EventType as EventType$1 } from '../../touch.js';
import { getDefaultHoverDelegate } from '../hover/hoverDelegateFactory.js';
import { renderLabelWithIcons } from '../iconLabel/iconLabels.js';
import { Color } from '../../../common/color.js';
import { Emitter } from '../../../common/event.js';
import { isMarkdownString, markdownStringEqual } from '../../../common/htmlContent.js';
import { Disposable } from '../../../common/lifecycle.js';
import { ThemeIcon } from '../../../common/themables.js';
import './button.css';
import { getBaseLayerHoverDelegate } from '../hover/hoverDelegate2.js';
import { safeSetInnerHtml } from '../../domSanitize.js';
({
buttonSeparator: Color.white.toString(),
buttonForeground: Color.white.toString()});
// Only allow a very limited set of inline html tags
const buttonSanitizerConfig = Object.freeze({
allowedTags: {
override: ['b', 'i', 'u', 'code', 'span'],
},
allowedAttributes: {
override: ['class'],
},
});
class Button extends Disposable {
get onDidClick() { return this._onDidClick.event; }
constructor(container, options) {
super();
this._label = '';
this._onDidClick = this._register(new Emitter());
this._onDidEscape = this._register(new Emitter());
this.options = options;
this._element = document.createElement('a');
this._element.classList.add('monaco-button');
this._element.tabIndex = 0;
this._element.setAttribute('role', 'button');
this._element.classList.toggle('secondary', !!options.secondary);
const background = options.secondary ? options.buttonSecondaryBackground : options.buttonBackground;
const foreground = options.secondary ? options.buttonSecondaryForeground : options.buttonForeground;
this._element.style.color = foreground || '';
this._element.style.backgroundColor = background || '';
if (options.supportShortLabel) {
this._labelShortElement = document.createElement('div');
this._labelShortElement.classList.add('monaco-button-label-short');
this._element.appendChild(this._labelShortElement);
this._labelElement = document.createElement('div');
this._labelElement.classList.add('monaco-button-label');
this._element.appendChild(this._labelElement);
this._element.classList.add('monaco-text-button-with-short-label');
}
if (typeof options.title === 'string') {
this.setTitle(options.title);
}
if (typeof options.ariaLabel === 'string') {
this._element.setAttribute('aria-label', options.ariaLabel);
}
container.appendChild(this._element);
this.enabled = !options.disabled;
this._register(Gesture.addTarget(this._element));
[EventType.CLICK, EventType$1.Tap].forEach(eventType => {
this._register(addDisposableListener(this._element, eventType, e => {
if (!this.enabled) {
EventHelper.stop(e);
return;
}
this._onDidClick.fire(e);
}));
});
this._register(addDisposableListener(this._element, EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
let eventHandled = false;
if (this.enabled && (event.equals(3 /* KeyCode.Enter */) || event.equals(10 /* KeyCode.Space */))) {
this._onDidClick.fire(e);
eventHandled = true;
}
else if (event.equals(9 /* KeyCode.Escape */)) {
this._onDidEscape.fire(e);
this._element.blur();
eventHandled = true;
}
if (eventHandled) {
EventHelper.stop(event, true);
}
}));
this._register(addDisposableListener(this._element, EventType.MOUSE_OVER, e => {
if (!this._element.classList.contains('disabled')) {
this.updateBackground(true);
}
}));
this._register(addDisposableListener(this._element, EventType.MOUSE_OUT, e => {
this.updateBackground(false); // restore standard styles
}));
// Also set hover background when button is focused for feedback
this.focusTracker = this._register(trackFocus(this._element));
this._register(this.focusTracker.onDidFocus(() => { if (this.enabled) {
this.updateBackground(true);
} }));
this._register(this.focusTracker.onDidBlur(() => { if (this.enabled) {
this.updateBackground(false);
} }));
}
dispose() {
super.dispose();
this._element.remove();
}
getContentElements(content) {
const elements = [];
for (let segment of renderLabelWithIcons(content)) {
if (typeof (segment) === 'string') {
segment = segment.trim();
// Ignore empty segment
if (segment === '') {
continue;
}
// Convert string segments to <span> nodes
const node = document.createElement('span');
node.textContent = segment;
elements.push(node);
}
else {
elements.push(segment);
}
}
return elements;
}
updateBackground(hover) {
let background;
if (this.options.secondary) {
background = hover ? this.options.buttonSecondaryHoverBackground : this.options.buttonSecondaryBackground;
}
else {
background = hover ? this.options.buttonHoverBackground : this.options.buttonBackground;
}
if (background) {
this._element.style.backgroundColor = background;
}
}
get element() {
return this._element;
}
set label(value) {
if (this._label === value) {
return;
}
if (isMarkdownString(this._label) && isMarkdownString(value) && markdownStringEqual(this._label, value)) {
return;
}
this._element.classList.add('monaco-text-button');
const labelElement = this.options.supportShortLabel ? this._labelElement : this._element;
if (isMarkdownString(value)) {
const rendered = renderMarkdown(value, undefined, document.createElement('span'));
rendered.dispose();
// Don't include outer `<p>`
// eslint-disable-next-line no-restricted-syntax
const root = rendered.element.querySelector('p')?.innerHTML;
if (root) {
safeSetInnerHtml(labelElement, root, buttonSanitizerConfig);
}
else {
reset(labelElement);
}
}
else {
if (this.options.supportIcons) {
reset(labelElement, ...this.getContentElements(value));
}
else {
labelElement.textContent = value;
}
}
let title = '';
if (typeof this.options.title === 'string') {
title = this.options.title;
}
else if (this.options.title) {
title = renderAsPlaintext(value);
}
this.setTitle(title);
this._setAriaLabel();
this._label = value;
}
get label() {
return this._label;
}
_setAriaLabel() {
if (typeof this.options.ariaLabel === 'string') {
this._element.setAttribute('aria-label', this.options.ariaLabel);
}
else if (typeof this.options.title === 'string') {
this._element.setAttribute('aria-label', this.options.title);
}
}
set icon(icon) {
this._setAriaLabel();
const oldIcons = Array.from(this._element.classList).filter(item => item.startsWith('codicon-'));
this._element.classList.remove(...oldIcons);
this._element.classList.add(...ThemeIcon.asClassNameArray(icon));
}
set enabled(value) {
if (value) {
this._element.classList.remove('disabled');
this._element.setAttribute('aria-disabled', String(false));
this._element.tabIndex = 0;
}
else {
this._element.classList.add('disabled');
this._element.setAttribute('aria-disabled', String(true));
}
}
get enabled() {
return !this._element.classList.contains('disabled');
}
setTitle(title) {
if (!this._hover && title !== '') {
this._hover = this._register(getBaseLayerHoverDelegate().setupManagedHover(this.options.hoverDelegate ?? getDefaultHoverDelegate('element'), this._element, title));
}
else if (this._hover) {
this._hover.update(title);
}
}
}
export { Button };
@@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.codicon-wrench-subaction {
opacity: 0.5;
}
@keyframes codicon-spin {
100% {
transform:rotate(360deg);
}
}
.codicon-sync.codicon-modifier-spin,
.codicon-loading.codicon-modifier-spin,
.codicon-gear.codicon-modifier-spin,
.codicon-notebook-state-executing.codicon-modifier-spin {
/* Use steps to throttle FPS to reduce CPU usage */
animation: codicon-spin 1.5s steps(30) infinite;
}
.codicon-modifier-disabled {
opacity: 0.4;
}
/* custom speed & easing for loading icon */
.codicon-loading,
.codicon-tree-item-loading::before {
animation-duration: 1s !important;
animation-timing-function: cubic-bezier(0.53, 0.21, 0.29, 0.67) !important;
}
@@ -0,0 +1 @@
export {}
@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
@font-face {
font-family: "codicon";
font-display: block;
src: url(./codicon.ttf) format("truetype");
}
.codicon[class*='codicon-'] {
font: normal normal normal 16px/1 codicon;
display: inline-block;
text-decoration: none;
text-rendering: auto;
text-align: center;
text-transform: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
-webkit-user-select: none;
}
/* icon rules are dynamically created by the platform theme service (see iconsStyleSheet.ts) */
@@ -0,0 +1 @@
export {}
@@ -0,0 +1,16 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.context-view {
position: absolute;
}
.context-view.fixed {
all: initial;
font-family: inherit;
font-size: 13px;
position: fixed;
color: inherit;
}
@@ -0,0 +1,298 @@
import { BrowserFeatures } from '../../canIUse.js';
import { $, hide, addStandardDisposableListener, clearNode, show, isHTMLElement, getDomNodePagePosition, getDomNodeZoomLevel, getTotalWidth, getTotalHeight, getActiveWindow, getWindow, isAncestor } from '../../dom.js';
import { Disposable, toDisposable, DisposableStore } from '../../../common/lifecycle.js';
import { isIOS } from '../../../common/platform.js';
import { Range } from '../../../common/range.js';
import './contextview.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
function isAnchor(obj) {
const anchor = obj;
return !!anchor && typeof anchor.x === 'number' && typeof anchor.y === 'number';
}
var LayoutAnchorMode;
(function (LayoutAnchorMode) {
LayoutAnchorMode[LayoutAnchorMode["AVOID"] = 0] = "AVOID";
LayoutAnchorMode[LayoutAnchorMode["ALIGN"] = 1] = "ALIGN";
})(LayoutAnchorMode || (LayoutAnchorMode = {}));
/**
* Lays out a one dimensional view next to an anchor in a viewport.
*
* @returns The view offset within the viewport.
*/
function layout(viewportSize, viewSize, anchor) {
const layoutAfterAnchorBoundary = anchor.mode === LayoutAnchorMode.ALIGN ? anchor.offset : anchor.offset + anchor.size;
const layoutBeforeAnchorBoundary = anchor.mode === LayoutAnchorMode.ALIGN ? anchor.offset + anchor.size : anchor.offset;
if (anchor.position === 0 /* LayoutAnchorPosition.Before */) {
if (viewSize <= viewportSize - layoutAfterAnchorBoundary) {
return layoutAfterAnchorBoundary; // happy case, lay it out after the anchor
}
if (viewSize <= layoutBeforeAnchorBoundary) {
return layoutBeforeAnchorBoundary - viewSize; // ok case, lay it out before the anchor
}
return Math.max(viewportSize - viewSize, 0); // sad case, lay it over the anchor
}
else {
if (viewSize <= layoutBeforeAnchorBoundary) {
return layoutBeforeAnchorBoundary - viewSize; // happy case, lay it out before the anchor
}
if (viewSize <= viewportSize - layoutAfterAnchorBoundary) {
return layoutAfterAnchorBoundary; // ok case, lay it out after the anchor
}
return 0; // sad case, lay it over the anchor
}
}
class ContextView extends Disposable {
static { this.BUBBLE_UP_EVENTS = ['click', 'keydown', 'focus', 'blur']; }
static { this.BUBBLE_DOWN_EVENTS = ['click']; }
constructor(container, domPosition) {
super();
this.container = null;
this.useFixedPosition = false;
this.useShadowDOM = false;
this.delegate = null;
this.toDisposeOnClean = Disposable.None;
this.toDisposeOnSetContainer = Disposable.None;
this.shadowRoot = null;
this.shadowRootHostElement = null;
this.view = $('.context-view');
hide(this.view);
this.setContainer(container, domPosition);
this._register(toDisposable(() => this.setContainer(null, 1 /* ContextViewDOMPosition.ABSOLUTE */)));
}
setContainer(container, domPosition) {
this.useFixedPosition = domPosition !== 1 /* ContextViewDOMPosition.ABSOLUTE */;
const usedShadowDOM = this.useShadowDOM;
this.useShadowDOM = domPosition === 3 /* ContextViewDOMPosition.FIXED_SHADOW */;
if (container === this.container && usedShadowDOM === this.useShadowDOM) {
return; // container is the same and no shadow DOM usage has changed
}
if (this.container) {
this.toDisposeOnSetContainer.dispose();
this.view.remove();
if (this.shadowRoot) {
this.shadowRoot = null;
this.shadowRootHostElement?.remove();
this.shadowRootHostElement = null;
}
this.container = null;
}
if (container) {
this.container = container;
if (this.useShadowDOM) {
this.shadowRootHostElement = $('.shadow-root-host');
this.container.appendChild(this.shadowRootHostElement);
this.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'open' });
const style = document.createElement('style');
style.textContent = SHADOW_ROOT_CSS;
this.shadowRoot.appendChild(style);
this.shadowRoot.appendChild(this.view);
this.shadowRoot.appendChild($('slot'));
}
else {
this.container.appendChild(this.view);
}
const toDisposeOnSetContainer = new DisposableStore();
ContextView.BUBBLE_UP_EVENTS.forEach(event => {
toDisposeOnSetContainer.add(addStandardDisposableListener(this.container, event, e => {
this.onDOMEvent(e, false);
}));
});
ContextView.BUBBLE_DOWN_EVENTS.forEach(event => {
toDisposeOnSetContainer.add(addStandardDisposableListener(this.container, event, e => {
this.onDOMEvent(e, true);
}, true));
});
this.toDisposeOnSetContainer = toDisposeOnSetContainer;
}
}
show(delegate) {
if (this.isVisible()) {
this.hide();
}
// Show static box
clearNode(this.view);
this.view.className = 'context-view monaco-component';
this.view.style.top = '0px';
this.view.style.left = '0px';
this.view.style.zIndex = `${2575 + (delegate.layer ?? 0)}`;
this.view.style.position = this.useFixedPosition ? 'fixed' : 'absolute';
show(this.view);
// Render content
this.toDisposeOnClean = delegate.render(this.view) || Disposable.None;
// Set active delegate
this.delegate = delegate;
// Layout
this.doLayout();
// Focus
this.delegate.focus?.();
}
getViewElement() {
return this.view;
}
layout() {
if (!this.isVisible()) {
return;
}
if (this.delegate.canRelayout === false && !(isIOS && BrowserFeatures.pointerEvents)) {
this.hide();
return;
}
this.delegate?.layout?.();
this.doLayout();
}
doLayout() {
// Check that we still have a delegate - this.delegate.layout may have hidden
if (!this.isVisible()) {
return;
}
// Get anchor
const anchor = this.delegate.getAnchor();
// Compute around
let around;
// Get the element's position and size (to anchor the view)
if (isHTMLElement(anchor)) {
const elementPosition = getDomNodePagePosition(anchor);
// In areas where zoom is applied to the element or its ancestors, we need to adjust the size of the element
// e.g. The title bar has counter zoom behavior meaning it applies the inverse of zoom level.
// Window Zoom Level: 1.5, Title Bar Zoom: 1/1.5, Size Multiplier: 1.5
const zoom = getDomNodeZoomLevel(anchor);
around = {
top: elementPosition.top * zoom,
left: elementPosition.left * zoom,
width: elementPosition.width * zoom,
height: elementPosition.height * zoom
};
}
else if (isAnchor(anchor)) {
around = {
top: anchor.y,
left: anchor.x,
width: anchor.width || 1,
height: anchor.height || 2
};
}
else {
around = {
top: anchor.posy,
left: anchor.posx,
// We are about to position the context view where the mouse
// cursor is. To prevent the view being exactly under the mouse
// when showing and thus potentially triggering an action within,
// we treat the mouse location like a small sized block element.
width: 2,
height: 2
};
}
const viewSizeWidth = getTotalWidth(this.view);
const viewSizeHeight = getTotalHeight(this.view);
const anchorPosition = this.delegate.anchorPosition ?? 0 /* AnchorPosition.BELOW */;
const anchorAlignment = this.delegate.anchorAlignment ?? 0 /* AnchorAlignment.LEFT */;
const anchorAxisAlignment = this.delegate.anchorAxisAlignment ?? 0 /* AnchorAxisAlignment.VERTICAL */;
let top;
let left;
const activeWindow = getActiveWindow();
if (anchorAxisAlignment === 0 /* AnchorAxisAlignment.VERTICAL */) {
const verticalAnchor = { offset: around.top - activeWindow.pageYOffset, size: around.height, position: anchorPosition === 0 /* AnchorPosition.BELOW */ ? 0 /* LayoutAnchorPosition.Before */ : 1 /* LayoutAnchorPosition.After */ };
const horizontalAnchor = { offset: around.left, size: around.width, position: anchorAlignment === 0 /* AnchorAlignment.LEFT */ ? 0 /* LayoutAnchorPosition.Before */ : 1 /* LayoutAnchorPosition.After */, mode: LayoutAnchorMode.ALIGN };
top = layout(activeWindow.innerHeight, viewSizeHeight, verticalAnchor) + activeWindow.pageYOffset;
// if view intersects vertically with anchor, we must avoid the anchor
if (Range.intersects({ start: top, end: top + viewSizeHeight }, { start: verticalAnchor.offset, end: verticalAnchor.offset + verticalAnchor.size })) {
horizontalAnchor.mode = LayoutAnchorMode.AVOID;
}
left = layout(activeWindow.innerWidth, viewSizeWidth, horizontalAnchor);
}
else {
const horizontalAnchor = { offset: around.left, size: around.width, position: anchorAlignment === 0 /* AnchorAlignment.LEFT */ ? 0 /* LayoutAnchorPosition.Before */ : 1 /* LayoutAnchorPosition.After */ };
const verticalAnchor = { offset: around.top, size: around.height, position: anchorPosition === 0 /* AnchorPosition.BELOW */ ? 0 /* LayoutAnchorPosition.Before */ : 1 /* LayoutAnchorPosition.After */, mode: LayoutAnchorMode.ALIGN };
left = layout(activeWindow.innerWidth, viewSizeWidth, horizontalAnchor);
// if view intersects horizontally with anchor, we must avoid the anchor
if (Range.intersects({ start: left, end: left + viewSizeWidth }, { start: horizontalAnchor.offset, end: horizontalAnchor.offset + horizontalAnchor.size })) {
verticalAnchor.mode = LayoutAnchorMode.AVOID;
}
top = layout(activeWindow.innerHeight, viewSizeHeight, verticalAnchor) + activeWindow.pageYOffset;
}
this.view.classList.remove('top', 'bottom', 'left', 'right');
this.view.classList.add(anchorPosition === 0 /* AnchorPosition.BELOW */ ? 'bottom' : 'top');
this.view.classList.add(anchorAlignment === 0 /* AnchorAlignment.LEFT */ ? 'left' : 'right');
this.view.classList.toggle('fixed', this.useFixedPosition);
const containerPosition = getDomNodePagePosition(this.container);
// Account for container scroll when positioning the context view
const containerScrollTop = this.container.scrollTop || 0;
const containerScrollLeft = this.container.scrollLeft || 0;
this.view.style.top = `${top - (this.useFixedPosition ? getDomNodePagePosition(this.view).top : containerPosition.top) + containerScrollTop}px`;
this.view.style.left = `${left - (this.useFixedPosition ? getDomNodePagePosition(this.view).left : containerPosition.left) + containerScrollLeft}px`;
this.view.style.width = 'initial';
}
hide(data) {
const delegate = this.delegate;
this.delegate = null;
if (delegate?.onHide) {
delegate.onHide(data);
}
this.toDisposeOnClean.dispose();
hide(this.view);
}
isVisible() {
return !!this.delegate;
}
onDOMEvent(e, onCapture) {
if (this.delegate) {
if (this.delegate.onDOMEvent) {
this.delegate.onDOMEvent(e, getWindow(e).document.activeElement);
}
else if (onCapture && !isAncestor(e.target, this.container)) {
this.hide();
}
}
}
dispose() {
this.hide();
super.dispose();
}
}
const SHADOW_ROOT_CSS = /* css */ `
:host {
all: initial; /* 1st rule so subsequent properties are reset. */
}
.codicon[class*='codicon-'] {
font: normal normal normal 16px/1 codicon;
display: inline-block;
text-decoration: none;
text-rendering: auto;
text-align: center;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
:host {
font-family: -apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "HelveticaNeue-Light", system-ui, "Ubuntu", "Droid Sans", sans-serif;
}
:host-context(.mac) { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
:host-context(.mac:lang(zh-Hans)) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; }
:host-context(.mac:lang(zh-Hant)) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; }
:host-context(.mac:lang(ja)) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; }
:host-context(.mac:lang(ko)) { font-family: -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Nanum Gothic", "AppleGothic", sans-serif; }
:host-context(.windows) { font-family: "Segoe WPC", "Segoe UI", sans-serif; }
:host-context(.windows:lang(zh-Hans)) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; }
:host-context(.windows:lang(zh-Hant)) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; }
:host-context(.windows:lang(ja)) { font-family: "Segoe WPC", "Segoe UI", "Yu Gothic UI", "Meiryo UI", sans-serif; }
:host-context(.windows:lang(ko)) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; }
:host-context(.linux) { font-family: system-ui, "Ubuntu", "Droid Sans", sans-serif; }
:host-context(.linux:lang(zh-Hans)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
:host-context(.linux:lang(zh-Hant)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; }
:host-context(.linux:lang(ja)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; }
:host-context(.linux:lang(ko)) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
`;
export { ContextView, LayoutAnchorMode, isAnchor, layout };
@@ -0,0 +1,24 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-count-badge {
padding: 3px 5px;
border-radius: 11px;
font-size: 11px;
min-width: 18px;
min-height: 18px;
line-height: 11px;
font-weight: normal;
text-align: center;
display: inline-block;
box-sizing: border-box;
}
.monaco-count-badge.long {
padding: 2px 3px;
border-radius: 2px;
min-height: auto;
line-height: normal;
}
@@ -0,0 +1,52 @@
import { append, $ } from '../../dom.js';
import { format } from '../../../common/strings.js';
import './countBadge.css';
import { Disposable, MutableDisposable, toDisposable } from '../../../common/lifecycle.js';
import { getBaseLayerHoverDelegate } from '../hover/hoverDelegate2.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class CountBadge extends Disposable {
constructor(container, options, styles) {
super();
this.options = options;
this.styles = styles;
this.count = 0;
this.hover = this._register(new MutableDisposable());
this.element = append(container, $('.monaco-count-badge'));
this._register(toDisposable(() => container.removeChild(this.element)));
this.countFormat = this.options.countFormat || '{0}';
this.titleFormat = this.options.titleFormat || '';
this.setCount(this.options.count || 0);
this.updateHover();
}
setCount(count) {
this.count = count;
this.render();
}
setTitleFormat(titleFormat) {
this.titleFormat = titleFormat;
this.updateHover();
this.render();
}
updateHover() {
if (this.titleFormat !== '' && !this.hover.value) {
this.hover.value = getBaseLayerHoverDelegate().setupDelayedHoverAtMouse(this.element, () => ({ content: format(this.titleFormat, this.count), appearance: { compact: true } }));
}
else if (this.titleFormat === '' && this.hover.value) {
this.hover.value = undefined;
}
}
render() {
this.element.textContent = format(this.countFormat, this.count);
this.element.style.backgroundColor = this.styles.badgeBackground ?? '';
this.element.style.color = this.styles.badgeForeground ?? '';
if (this.styles.badgeBorder) {
this.element.style.border = `1px solid ${this.styles.badgeBorder}`;
}
}
}
export { CountBadge };
+28
View File
@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-drag-image {
display: inline-block;
padding: 1px 7px;
border-radius: 10px;
font-size: 12px;
position: absolute;
z-index: 1000;
/* Default styles */
background-color: var(--vscode-list-activeSelectionBackground);
color: var(--vscode-list-activeSelectionForeground);
outline: 1px solid var(--vscode-list-focusOutline);
outline-offset: -1px;
/*
* Browsers apply an effect to the drag image when the div becomes too
* large which makes them unreadable. Use max width so it does not happen
*/
max-width: 120px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
+28
View File
@@ -0,0 +1,28 @@
import { $ } from '../../dom.js';
import './dnd.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
function applyDragImage(event, container, label, extraClasses = []) {
if (!event.dataTransfer) {
return;
}
const dragImage = $('.monaco-drag-image');
dragImage.textContent = label;
dragImage.classList.add(...extraClasses);
const getDragImageContainer = (e) => {
while (e && !e.classList.contains('monaco-workbench')) {
e = e.parentElement;
}
return e || container.ownerDocument.body;
};
const dragContainer = getDragImageContainer(container);
dragContainer.appendChild(dragImage);
event.dataTransfer.setDragImage(dragImage, -10, -10);
// Removes the element when the DND operation is done
setTimeout(() => dragImage.remove(), 0);
}
export { applyDragImage };
@@ -0,0 +1,46 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-dropdown {
height: 100%;
padding: 0;
}
.monaco-dropdown > .dropdown-label {
cursor: pointer;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.monaco-dropdown > .dropdown-label > .action-label.disabled {
cursor: default;
}
.monaco-dropdown-with-primary {
display: flex !important;
flex-direction: row;
border-radius: 5px;
}
.monaco-dropdown-with-primary > .action-container > .action-label {
margin-right: 0;
}
.monaco-dropdown-with-primary > .dropdown-action-container > .monaco-dropdown > .dropdown-label .codicon[class*='codicon-'] {
font-size: 12px;
padding-left: 0px;
padding-right: 0px;
line-height: 16px;
margin-left: -3px;
}
.monaco-dropdown-with-primary > .dropdown-action-container > .monaco-dropdown > .dropdown-label > .action-label {
display: block;
background-size: 16px;
background-position: center center;
background-repeat: no-repeat;
}
@@ -0,0 +1,141 @@
import { append, $, EventType, addDisposableListener, EventHelper, isMouseEvent } from '../../dom.js';
import { StandardKeyboardEvent } from '../../keyboardEvent.js';
import { EventType as EventType$1, Gesture } from '../../touch.js';
import { ActionRunner } from '../../../common/actions.js';
import { Emitter } from '../../../common/event.js';
import './dropdown.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class BaseDropdown extends ActionRunner {
constructor(container, options) {
super();
this._onDidChangeVisibility = this._register(new Emitter());
this.onDidChangeVisibility = this._onDidChangeVisibility.event;
this._element = append(container, $('.monaco-dropdown'));
this._label = append(this._element, $('.dropdown-label'));
let labelRenderer = options.labelRenderer;
if (!labelRenderer) {
labelRenderer = (container) => {
container.textContent = options.label || '';
return null;
};
}
for (const event of [EventType.CLICK, EventType.MOUSE_DOWN, EventType$1.Tap]) {
this._register(addDisposableListener(this.element, event, e => EventHelper.stop(e, true))); // prevent default click behaviour to trigger
}
for (const event of [EventType.MOUSE_DOWN, EventType$1.Tap]) {
this._register(addDisposableListener(this._label, event, e => {
if (isMouseEvent(e) && e.button !== 0) {
// prevent right click trigger to allow separate context menu (https://github.com/microsoft/vscode/issues/151064)
return;
}
if (this.visible) {
this.hide();
}
else {
this.show();
}
}));
}
this._register(addDisposableListener(this._label, EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
if (event.equals(3 /* KeyCode.Enter */) || event.equals(10 /* KeyCode.Space */)) {
EventHelper.stop(e, true); // https://github.com/microsoft/vscode/issues/57997
if (this.visible) {
this.hide();
}
else {
this.show();
}
}
}));
const cleanupFn = labelRenderer(this._label);
if (cleanupFn) {
this._register(cleanupFn);
}
this._register(Gesture.addTarget(this._label));
}
get element() {
return this._element;
}
show() {
if (!this.visible) {
this.visible = true;
this._onDidChangeVisibility.fire(true);
}
}
hide() {
if (this.visible) {
this.visible = false;
this._onDidChangeVisibility.fire(false);
}
}
dispose() {
super.dispose();
this.hide();
if (this.boxContainer) {
this.boxContainer.remove();
this.boxContainer = undefined;
}
if (this.contents) {
this.contents.remove();
this.contents = undefined;
}
if (this._label) {
this._label.remove();
this._label = undefined;
}
}
}
class DropdownMenu extends BaseDropdown {
constructor(container, _options) {
super(container, _options);
this._options = _options;
this._actions = [];
this.actions = _options.actions || [];
}
set menuOptions(options) {
this._menuOptions = options;
}
get menuOptions() {
return this._menuOptions;
}
get actions() {
if (this._options.actionProvider) {
return this._options.actionProvider.getActions();
}
return this._actions;
}
set actions(actions) {
this._actions = actions;
}
show() {
super.show();
this.element.classList.add('active');
this._options.contextMenuProvider.showContextMenu({
getAnchor: () => this.element,
getActions: () => this.actions,
getActionsContext: () => this.menuOptions ? this.menuOptions.context : null,
getActionViewItem: (action, options) => this.menuOptions && this.menuOptions.actionViewItemProvider ? this.menuOptions.actionViewItemProvider(action, options) : undefined,
getKeyBinding: action => this.menuOptions && this.menuOptions.getKeyBinding ? this.menuOptions.getKeyBinding(action) : undefined,
getMenuClassName: () => this._options.menuClassName || '',
onHide: () => this.onHide(),
actionRunner: this.menuOptions ? this.menuOptions.actionRunner : undefined,
anchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : 0 /* AnchorAlignment.LEFT */,
domForShadowRoot: this._options.menuAsChild ? this.element : undefined,
skipTelemetry: this._options.skipTelemetry
});
}
hide() {
super.hide();
}
onHide() {
this.hide();
this.element.classList.remove('active');
}
}
export { BaseDropdown, DropdownMenu };
@@ -0,0 +1,109 @@
import { Emitter } from '../../../common/event.js';
import { append, $ } from '../../dom.js';
import { BaseActionViewItem } from '../actionbar/actionViewItems.js';
import { getBaseLayerHoverDelegate } from '../hover/hoverDelegate2.js';
import { getDefaultHoverDelegate } from '../hover/hoverDelegateFactory.js';
import './dropdown.css';
import { DropdownMenu } from './dropdown.js';
class DropdownMenuActionViewItem extends BaseActionViewItem {
get onDidChangeVisibility() { return this._onDidChangeVisibility.event; }
constructor(action, menuActionsOrProvider, contextMenuProvider, options = Object.create(null)) {
super(null, action, options);
this.actionItem = null;
this._onDidChangeVisibility = this._register(new Emitter());
this.menuActionsOrProvider = menuActionsOrProvider;
this.contextMenuProvider = contextMenuProvider;
this.options = options;
if (this.options.actionRunner) {
this.actionRunner = this.options.actionRunner;
}
}
render(container) {
this.actionItem = container;
const labelRenderer = (el) => {
this.element = append(el, $('a.action-label'));
return this.renderLabel(this.element);
};
const isActionsArray = Array.isArray(this.menuActionsOrProvider);
const options = {
contextMenuProvider: this.contextMenuProvider,
labelRenderer: labelRenderer,
menuAsChild: this.options.menuAsChild,
actions: isActionsArray ? this.menuActionsOrProvider : undefined,
actionProvider: isActionsArray ? undefined : this.menuActionsOrProvider,
skipTelemetry: this.options.skipTelemetry
};
this.dropdownMenu = this._register(new DropdownMenu(container, options));
this._register(this.dropdownMenu.onDidChangeVisibility(visible => {
this.element?.setAttribute('aria-expanded', `${visible}`);
this._onDidChangeVisibility.fire(visible);
}));
this.dropdownMenu.menuOptions = {
actionViewItemProvider: this.options.actionViewItemProvider,
actionRunner: this.actionRunner,
getKeyBinding: this.options.keybindingProvider,
context: this._context
};
if (this.options.anchorAlignmentProvider) {
const that = this;
this.dropdownMenu.menuOptions = {
...this.dropdownMenu.menuOptions,
get anchorAlignment() {
return that.options.anchorAlignmentProvider();
}
};
}
this.updateTooltip();
this.updateEnabled();
}
renderLabel(element) {
let classNames = [];
if (typeof this.options.classNames === 'string') {
classNames = this.options.classNames.split(/\s+/g).filter(s => !!s);
}
else if (this.options.classNames) {
classNames = this.options.classNames;
}
// todo@aeschli: remove codicon, should come through `this.options.classNames`
if (!classNames.find(c => c === 'icon')) {
classNames.push('codicon');
}
element.classList.add(...classNames);
if (this._action.label) {
this._register(getBaseLayerHoverDelegate().setupManagedHover(this.options.hoverDelegate ?? getDefaultHoverDelegate('mouse'), element, this._action.label));
}
return null;
}
getTooltip() {
let title = null;
if (this.action.tooltip) {
title = this.action.tooltip;
}
else if (this.action.label) {
title = this.action.label;
}
return title ?? undefined;
}
setActionContext(newContext) {
super.setActionContext(newContext);
if (this.dropdownMenu) {
if (this.dropdownMenu.menuOptions) {
this.dropdownMenu.menuOptions.context = newContext;
}
else {
this.dropdownMenu.menuOptions = { context: newContext };
}
}
}
show() {
this.dropdownMenu?.show();
}
updateEnabled() {
const disabled = !this.action.enabled;
this.actionItem?.classList.toggle('disabled', disabled);
this.element?.classList.toggle('disabled', disabled);
}
}
export { DropdownMenuActionViewItem };
@@ -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.
*--------------------------------------------------------------------------------------------*/
/* ---------- Find input ---------- */
.monaco-findInput {
position: relative;
}
.monaco-findInput .monaco-inputbox {
font-size: 13px;
width: 100%;
}
.monaco-findInput > .controls {
position: absolute;
top: 3px;
right: 2px;
}
.vs .monaco-findInput.disabled {
background-color: #E1E1E1;
}
/* Theming */
.vs-dark .monaco-findInput.disabled {
background-color: #333;
}
/* Highlighting */
.monaco-findInput.highlight-0 .controls,
.hc-light .monaco-findInput.highlight-0 .controls {
animation: monaco-findInput-highlight-0 100ms linear 0s;
}
.monaco-findInput.highlight-1 .controls,
.hc-light .monaco-findInput.highlight-1 .controls {
animation: monaco-findInput-highlight-1 100ms linear 0s;
}
.hc-black .monaco-findInput.highlight-0 .controls,
.vs-dark .monaco-findInput.highlight-0 .controls {
animation: monaco-findInput-highlight-dark-0 100ms linear 0s;
}
.hc-black .monaco-findInput.highlight-1 .controls,
.vs-dark .monaco-findInput.highlight-1 .controls {
animation: monaco-findInput-highlight-dark-1 100ms linear 0s;
}
@keyframes monaco-findInput-highlight-0 {
0% { background: rgba(253, 255, 0, 0.8); }
100% { background: transparent; }
}
@keyframes monaco-findInput-highlight-1 {
0% { background: rgba(253, 255, 0, 0.8); }
/* Made intentionally different such that the CSS minifier does not collapse the two animations into a single one*/
99% { background: transparent; }
}
@keyframes monaco-findInput-highlight-dark-0 {
0% { background: rgba(255, 255, 255, 0.44); }
100% { background: transparent; }
}
@keyframes monaco-findInput-highlight-dark-1 {
0% { background: rgba(255, 255, 255, 0.44); }
/* Made intentionally different such that the CSS minifier does not collapse the two animations into a single one*/
99% { background: transparent; }
}
@@ -0,0 +1,294 @@
import { EventHelper, addDisposableListener } from '../../dom.js';
import { RegexToggle, WholeWordsToggle, CaseSensitiveToggle } from './findInputToggles.js';
import { HistoryInputBox } from '../inputbox/inputBox.js';
import { Widget } from '../widget.js';
import { Emitter } from '../../../common/event.js';
import './findInput.css';
import { localize } from '../../../../nls.js';
import { MutableDisposable, DisposableStore } from '../../../common/lifecycle.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const NLS_DEFAULT_LABEL = localize(1, "input");
class FindInput extends Widget {
get onDidOptionChange() { return this._onDidOptionChange.event; }
get onKeyDown() { return this._onKeyDown.event; }
get onMouseDown() { return this._onMouseDown.event; }
get onCaseSensitiveKeyDown() { return this._onCaseSensitiveKeyDown.event; }
get onRegexKeyDown() { return this._onRegexKeyDown.event; }
constructor(parent, contextViewProvider, options) {
super();
this.fixFocusOnOptionClickEnabled = true;
this.imeSessionInProgress = false;
this.additionalTogglesDisposables = this._register(new MutableDisposable());
this.additionalToggles = [];
this._onDidOptionChange = this._register(new Emitter());
this._onKeyDown = this._register(new Emitter());
this._onMouseDown = this._register(new Emitter());
this._onInput = this._register(new Emitter());
this._onKeyUp = this._register(new Emitter());
this._onCaseSensitiveKeyDown = this._register(new Emitter());
this._onRegexKeyDown = this._register(new Emitter());
this._lastHighlightFindOptions = 0;
this.placeholder = options.placeholder || '';
this.validation = options.validation;
this.label = options.label || NLS_DEFAULT_LABEL;
this.showCommonFindToggles = !!options.showCommonFindToggles;
const appendCaseSensitiveLabel = options.appendCaseSensitiveLabel || '';
const appendWholeWordsLabel = options.appendWholeWordsLabel || '';
const appendRegexLabel = options.appendRegexLabel || '';
const flexibleHeight = !!options.flexibleHeight;
const flexibleWidth = !!options.flexibleWidth;
const flexibleMaxHeight = options.flexibleMaxHeight;
this.domNode = document.createElement('div');
this.domNode.classList.add('monaco-findInput');
this.inputBox = this._register(new HistoryInputBox(this.domNode, contextViewProvider, {
placeholder: this.placeholder || '',
ariaLabel: this.label || '',
validationOptions: {
validation: this.validation
},
showHistoryHint: options.showHistoryHint,
flexibleHeight,
flexibleWidth,
flexibleMaxHeight,
inputBoxStyles: options.inputBoxStyles,
history: options.history
}));
if (this.showCommonFindToggles) {
const hoverLifecycleOptions = options?.hoverLifecycleOptions || { groupId: 'find-input' };
this.regex = this._register(new RegexToggle({
appendTitle: appendRegexLabel,
isChecked: false,
hoverLifecycleOptions,
...options.toggleStyles
}));
this._register(this.regex.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.regex.onKeyDown(e => {
this._onRegexKeyDown.fire(e);
}));
this.wholeWords = this._register(new WholeWordsToggle({
appendTitle: appendWholeWordsLabel,
isChecked: false,
hoverLifecycleOptions,
...options.toggleStyles
}));
this._register(this.wholeWords.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this.caseSensitive = this._register(new CaseSensitiveToggle({
appendTitle: appendCaseSensitiveLabel,
isChecked: false,
hoverLifecycleOptions,
...options.toggleStyles
}));
this._register(this.caseSensitive.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.caseSensitive.onKeyDown(e => {
this._onCaseSensitiveKeyDown.fire(e);
}));
// Arrow-Key support to navigate between options
const indexes = [this.caseSensitive.domNode, this.wholeWords.domNode, this.regex.domNode];
this.onkeydown(this.domNode, (event) => {
if (event.equals(15 /* KeyCode.LeftArrow */) || event.equals(17 /* KeyCode.RightArrow */) || event.equals(9 /* KeyCode.Escape */)) {
const index = indexes.indexOf(this.domNode.ownerDocument.activeElement);
if (index >= 0) {
let newIndex = -1;
if (event.equals(17 /* KeyCode.RightArrow */)) {
newIndex = (index + 1) % indexes.length;
}
else if (event.equals(15 /* KeyCode.LeftArrow */)) {
if (index === 0) {
newIndex = indexes.length - 1;
}
else {
newIndex = index - 1;
}
}
if (event.equals(9 /* KeyCode.Escape */)) {
indexes[index].blur();
this.inputBox.focus();
}
else if (newIndex >= 0) {
indexes[newIndex].focus();
}
EventHelper.stop(event, true);
}
}
});
}
this.controls = document.createElement('div');
this.controls.className = 'controls';
this.controls.style.display = this.showCommonFindToggles ? '' : 'none';
if (this.caseSensitive) {
this.controls.append(this.caseSensitive.domNode);
}
if (this.wholeWords) {
this.controls.appendChild(this.wholeWords.domNode);
}
if (this.regex) {
this.controls.appendChild(this.regex.domNode);
}
this.setAdditionalToggles(options?.additionalToggles);
if (this.controls) {
this.domNode.appendChild(this.controls);
}
parent?.appendChild(this.domNode);
this._register(addDisposableListener(this.inputBox.inputElement, 'compositionstart', (e) => {
this.imeSessionInProgress = true;
}));
this._register(addDisposableListener(this.inputBox.inputElement, 'compositionend', (e) => {
this.imeSessionInProgress = false;
this._onInput.fire();
}));
this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));
this.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));
this.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());
this.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));
}
get onDidChange() {
return this.inputBox.onDidChange;
}
layout(style) {
this.inputBox.layout();
this.updateInputBoxPadding(style.collapsedFindWidget);
}
enable() {
this.domNode.classList.remove('disabled');
this.inputBox.enable();
this.regex?.enable();
this.wholeWords?.enable();
this.caseSensitive?.enable();
for (const toggle of this.additionalToggles) {
toggle.enable();
}
}
disable() {
this.domNode.classList.add('disabled');
this.inputBox.disable();
this.regex?.disable();
this.wholeWords?.disable();
this.caseSensitive?.disable();
for (const toggle of this.additionalToggles) {
toggle.disable();
}
}
setFocusInputOnOptionClick(value) {
this.fixFocusOnOptionClickEnabled = value;
}
setEnabled(enabled) {
if (enabled) {
this.enable();
}
else {
this.disable();
}
}
setAdditionalToggles(toggles) {
for (const currentToggle of this.additionalToggles) {
currentToggle.domNode.remove();
}
this.additionalToggles = [];
this.additionalTogglesDisposables.value = new DisposableStore();
for (const toggle of toggles ?? []) {
this.additionalTogglesDisposables.value.add(toggle);
this.controls.appendChild(toggle.domNode);
this.additionalTogglesDisposables.value.add(toggle.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
}));
this.additionalToggles.push(toggle);
}
if (this.additionalToggles.length > 0) {
this.controls.style.display = '';
}
this.updateInputBoxPadding();
}
updateInputBoxPadding(controlsHidden = false) {
if (controlsHidden) {
this.inputBox.paddingRight = 0;
}
else {
this.inputBox.paddingRight =
((this.caseSensitive?.width() ?? 0) + (this.wholeWords?.width() ?? 0) + (this.regex?.width() ?? 0))
+ this.additionalToggles.reduce((r, t) => r + t.width(), 0);
}
}
getValue() {
return this.inputBox.value;
}
setValue(value) {
if (this.inputBox.value !== value) {
this.inputBox.value = value;
}
}
select() {
this.inputBox.select();
}
focus() {
this.inputBox.focus();
}
getCaseSensitive() {
return this.caseSensitive?.checked ?? false;
}
setCaseSensitive(value) {
if (this.caseSensitive) {
this.caseSensitive.checked = value;
}
}
getWholeWords() {
return this.wholeWords?.checked ?? false;
}
setWholeWords(value) {
if (this.wholeWords) {
this.wholeWords.checked = value;
}
}
getRegex() {
return this.regex?.checked ?? false;
}
setRegex(value) {
if (this.regex) {
this.regex.checked = value;
this.validate();
}
}
focusOnCaseSensitive() {
this.caseSensitive?.focus();
}
highlightFindOptions() {
this.domNode.classList.remove('highlight-' + (this._lastHighlightFindOptions));
this._lastHighlightFindOptions = 1 - this._lastHighlightFindOptions;
this.domNode.classList.add('highlight-' + (this._lastHighlightFindOptions));
}
validate() {
this.inputBox.validate();
}
showMessage(message) {
this.inputBox.showMessage(message);
}
clearMessage() {
this.inputBox.hideMessage();
}
}
export { FindInput };
@@ -0,0 +1,52 @@
import { Toggle } from '../toggle/toggle.js';
import { Codicon } from '../../../common/codicons.js';
import { localize } from '../../../../nls.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const NLS_CASE_SENSITIVE_TOGGLE_LABEL = localize(2, "Match Case");
const NLS_WHOLE_WORD_TOGGLE_LABEL = localize(3, "Match Whole Word");
const NLS_REGEX_TOGGLE_LABEL = localize(4, "Use Regular Expression");
class CaseSensitiveToggle extends Toggle {
constructor(opts) {
super({
icon: Codicon.caseSensitive,
title: NLS_CASE_SENSITIVE_TOGGLE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
hoverLifecycleOptions: opts.hoverLifecycleOptions,
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground
});
}
}
class WholeWordsToggle extends Toggle {
constructor(opts) {
super({
icon: Codicon.wholeWord,
title: NLS_WHOLE_WORD_TOGGLE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
hoverLifecycleOptions: opts.hoverLifecycleOptions,
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground
});
}
}
class RegexToggle extends Toggle {
constructor(opts) {
super({
icon: Codicon.regex,
title: NLS_REGEX_TOGGLE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
hoverLifecycleOptions: opts.hoverLifecycleOptions,
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground
});
}
}
export { CaseSensitiveToggle, RegexToggle, WholeWordsToggle };
@@ -0,0 +1,176 @@
import { EventHelper } from '../../dom.js';
import { Toggle } from '../toggle/toggle.js';
import { HistoryInputBox } from '../inputbox/inputBox.js';
import { Widget } from '../widget.js';
import { Codicon } from '../../../common/codicons.js';
import { Emitter } from '../../../common/event.js';
import './findInput.css';
import { localize } from '../../../../nls.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const NLS_DEFAULT_LABEL = localize(5, "input");
const NLS_PRESERVE_CASE_LABEL = localize(6, "Preserve Case");
class PreserveCaseToggle extends Toggle {
constructor(opts) {
super({
// TODO: does this need its own icon?
icon: Codicon.preserveCase,
title: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,
isChecked: opts.isChecked,
hoverLifecycleOptions: opts.hoverLifecycleOptions,
inputActiveOptionBorder: opts.inputActiveOptionBorder,
inputActiveOptionForeground: opts.inputActiveOptionForeground,
inputActiveOptionBackground: opts.inputActiveOptionBackground,
});
}
}
class ReplaceInput extends Widget {
get onDidOptionChange() { return this._onDidOptionChange.event; }
get onKeyDown() { return this._onKeyDown.event; }
get onPreserveCaseKeyDown() { return this._onPreserveCaseKeyDown.event; }
constructor(parent, contextViewProvider, _showOptionButtons, options) {
super();
this._showOptionButtons = _showOptionButtons;
this.fixFocusOnOptionClickEnabled = true;
this.cachedOptionsWidth = 0;
this._onDidOptionChange = this._register(new Emitter());
this._onKeyDown = this._register(new Emitter());
this._onMouseDown = this._register(new Emitter());
this._onInput = this._register(new Emitter());
this._onKeyUp = this._register(new Emitter());
this._onPreserveCaseKeyDown = this._register(new Emitter());
this.contextViewProvider = contextViewProvider;
this.placeholder = options.placeholder || '';
this.validation = options.validation;
this.label = options.label || NLS_DEFAULT_LABEL;
const appendPreserveCaseLabel = options.appendPreserveCaseLabel || '';
const history = options.history || new Set([]);
const flexibleHeight = !!options.flexibleHeight;
const flexibleWidth = !!options.flexibleWidth;
const flexibleMaxHeight = options.flexibleMaxHeight;
this.domNode = document.createElement('div');
this.domNode.classList.add('monaco-findInput');
this.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {
ariaLabel: this.label || '',
placeholder: this.placeholder || '',
validationOptions: {
validation: this.validation
},
history,
showHistoryHint: options.showHistoryHint,
flexibleHeight,
flexibleWidth,
flexibleMaxHeight,
inputBoxStyles: options.inputBoxStyles
}));
this.preserveCase = this._register(new PreserveCaseToggle({
appendTitle: appendPreserveCaseLabel,
isChecked: false,
hoverLifecycleOptions: options.hoverLifecycleOptions,
...options.toggleStyles
}));
this._register(this.preserveCase.onChange(viaKeyboard => {
this._onDidOptionChange.fire(viaKeyboard);
if (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {
this.inputBox.focus();
}
this.validate();
}));
this._register(this.preserveCase.onKeyDown(e => {
this._onPreserveCaseKeyDown.fire(e);
}));
if (this._showOptionButtons) {
this.cachedOptionsWidth = this.preserveCase.width();
}
else {
this.cachedOptionsWidth = 0;
}
// Arrow-Key support to navigate between options
const indexes = [this.preserveCase.domNode];
this.onkeydown(this.domNode, (event) => {
if (event.equals(15 /* KeyCode.LeftArrow */) || event.equals(17 /* KeyCode.RightArrow */) || event.equals(9 /* KeyCode.Escape */)) {
const index = indexes.indexOf(this.domNode.ownerDocument.activeElement);
if (index >= 0) {
let newIndex = -1;
if (event.equals(17 /* KeyCode.RightArrow */)) {
newIndex = (index + 1) % indexes.length;
}
else if (event.equals(15 /* KeyCode.LeftArrow */)) {
if (index === 0) {
newIndex = indexes.length - 1;
}
else {
newIndex = index - 1;
}
}
if (event.equals(9 /* KeyCode.Escape */)) {
indexes[index].blur();
this.inputBox.focus();
}
else if (newIndex >= 0) {
indexes[newIndex].focus();
}
EventHelper.stop(event, true);
}
}
});
const controls = document.createElement('div');
controls.className = 'controls';
controls.style.display = this._showOptionButtons ? 'block' : 'none';
controls.appendChild(this.preserveCase.domNode);
this.domNode.appendChild(controls);
parent?.appendChild(this.domNode);
this.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));
this.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));
this.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());
this.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));
}
enable() {
this.domNode.classList.remove('disabled');
this.inputBox.enable();
this.preserveCase.enable();
}
disable() {
this.domNode.classList.add('disabled');
this.inputBox.disable();
this.preserveCase.disable();
}
setEnabled(enabled) {
if (enabled) {
this.enable();
}
else {
this.disable();
}
}
select() {
this.inputBox.select();
}
focus() {
this.inputBox.focus();
}
getPreserveCase() {
return this.preserveCase.checked;
}
setPreserveCase(value) {
this.preserveCase.checked = value;
}
focusOnPreserve() {
this.preserveCase.focus();
}
validate() {
this.inputBox?.validate();
}
set width(newWidth) {
this.inputBox.paddingRight = this.cachedOptionsWidth;
this.domNode.style.width = newWidth + 'px';
}
dispose() {
super.dispose();
}
}
export { ReplaceInput };
@@ -0,0 +1,129 @@
import { append, $, reset } from '../../dom.js';
import { getBaseLayerHoverDelegate } from '../hover/hoverDelegate2.js';
import { getDefaultHoverDelegate } from '../hover/hoverDelegateFactory.js';
import { renderLabelWithIcons } from '../iconLabel/iconLabels.js';
import { Disposable } from '../../../common/lifecycle.js';
import { equals } from '../../../common/objects.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* A widget which can render a label with substring highlights, often
* originating from a filter function like the fuzzy matcher.
*/
class HighlightedLabel extends Disposable {
/**
* Create a new {@link HighlightedLabel}.
*
* @param container The parent container to append to.
*/
constructor(container, options) {
super();
this.options = options;
this.text = '';
this.title = '';
this.highlights = [];
this.didEverRender = false;
this.domNode = append(container, $('span.monaco-highlighted-label'));
}
/**
* The label's DOM node.
*/
get element() {
return this.domNode;
}
/**
* Set the label and highlights.
*
* @param text The label to display.
* @param highlights The ranges to highlight.
* @param title An optional title for the hover tooltip.
* @param escapeNewLines Whether to escape new lines.
* @returns
*/
set(text, highlights = [], title = '', escapeNewLines, supportIcons) {
if (!text) {
text = '';
}
if (escapeNewLines) {
// adjusts highlights inplace
text = HighlightedLabel.escapeNewLines(text, highlights);
}
if (this.didEverRender && this.text === text && this.title === title && equals(this.highlights, highlights)) {
return;
}
this.text = text;
this.title = title;
this.highlights = highlights;
this.render(supportIcons);
}
render(supportIcons) {
const children = [];
let pos = 0;
for (const highlight of this.highlights) {
if (highlight.end === highlight.start) {
continue;
}
if (pos < highlight.start) {
const substring = this.text.substring(pos, highlight.start);
if (supportIcons) {
children.push(...renderLabelWithIcons(substring));
}
else {
children.push(substring);
}
pos = highlight.start;
}
const substring = this.text.substring(pos, highlight.end);
const element = $('span.highlight', undefined, ...supportIcons ? renderLabelWithIcons(substring) : [substring]);
if (highlight.extraClasses) {
element.classList.add(...highlight.extraClasses);
}
children.push(element);
pos = highlight.end;
}
if (pos < this.text.length) {
const substring = this.text.substring(pos);
if (supportIcons) {
children.push(...renderLabelWithIcons(substring));
}
else {
children.push(substring);
}
}
reset(this.domNode, ...children);
if (!this.customHover && this.title !== '') {
const hoverDelegate = this.options?.hoverDelegate ?? getDefaultHoverDelegate('mouse');
this.customHover = this._register(getBaseLayerHoverDelegate().setupManagedHover(hoverDelegate, this.domNode, this.title));
}
else if (this.customHover) {
this.customHover.update(this.title);
}
this.didEverRender = true;
}
static escapeNewLines(text, highlights) {
let total = 0;
let extra = 0;
return text.replace(/\r\n|\r|\n/g, (match, offset) => {
extra = match === '\r\n' ? -1 : 0;
offset += total;
for (const highlight of highlights) {
if (highlight.end <= offset) {
continue;
}
if (highlight.start >= offset) {
highlight.start += extra;
}
if (highlight.end >= offset) {
highlight.end += extra;
}
}
total += extra;
return '\u23CE';
});
}
}
export { HighlightedLabel };
@@ -0,0 +1,11 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
function isManagedHoverTooltipMarkdownString(obj) {
const candidate = obj;
return typeof candidate === 'object' && 'markdown' in candidate && 'markdownNotSupportedFallback' in candidate;
}
// #endregion Managed hover
export { isManagedHoverTooltipMarkdownString };
@@ -0,0 +1,39 @@
import { Disposable } from '../../../common/lifecycle.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
let baseHoverDelegate = {
showInstantHover: () => undefined,
showDelayedHover: () => undefined,
setupDelayedHover: () => Disposable.None,
setupDelayedHoverAtMouse: () => Disposable.None,
hideHover: () => undefined,
showAndFocusLastHover: () => undefined,
setupManagedHover: () => ({
dispose: () => undefined,
show: () => undefined,
hide: () => undefined,
update: () => undefined,
}),
showManagedHover: () => undefined
};
/**
* Sets the hover delegate for use **only in the `base/` layer**.
*/
function setBaseLayerHoverDelegate(hoverDelegate) {
baseHoverDelegate = hoverDelegate;
}
/**
* Gets the hover delegate for use **only in the `base/` layer**.
*
* Since the hover service depends on various platform services, this delegate essentially bypasses
* the standard dependency injection mechanism by injecting a global hover service at start up. The
* only reason this should be used is if `IHoverService` is not available.
*/
function getBaseLayerHoverDelegate() {
return baseHoverDelegate;
}
export { getBaseLayerHoverDelegate, setBaseLayerHoverDelegate };
@@ -0,0 +1,34 @@
import { Lazy } from '../../../common/lazy.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const nullHoverDelegateFactory = () => ({
get delay() { return -1; },
dispose: () => { },
showHover: () => { return undefined; },
});
let hoverDelegateFactory = nullHoverDelegateFactory;
const defaultHoverDelegateMouse = new Lazy(() => hoverDelegateFactory('mouse', false));
const defaultHoverDelegateElement = new Lazy(() => hoverDelegateFactory('element', false));
// TODO: Remove when getDefaultHoverDelegate is no longer used
function setHoverDelegateFactory(hoverDelegateProvider) {
hoverDelegateFactory = hoverDelegateProvider;
}
// TODO: Refine type for use in new IHoverService interface
function getDefaultHoverDelegate(placement) {
if (placement === 'element') {
return defaultHoverDelegateElement.value;
}
return defaultHoverDelegateMouse.value;
}
// TODO: Create equivalent in IHoverService
function createInstantHoverDelegate() {
// Creates a hover delegate with instant hover enabled.
// This hover belongs to the consumer and requires the them to dispose it.
// Instant hover only makes sense for 'element' placement.
return hoverDelegateFactory('element', true);
}
export { createInstantHoverDelegate, getDefaultHoverDelegate, setHoverDelegateFactory };
@@ -0,0 +1,225 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-hover {
cursor: default;
position: absolute;
overflow: hidden;
user-select: text;
-webkit-user-select: text;
box-sizing: border-box;
line-height: 1.5em;
white-space: var(--vscode-hover-whiteSpace, normal);
}
.monaco-hover.fade-in {
animation: fadein 100ms linear;
}
.monaco-hover.hidden {
display: none;
}
.monaco-hover a:hover:not(.disabled) {
cursor: pointer;
}
.monaco-hover .hover-contents:not(.html-hover-contents) {
padding: 4px 8px;
}
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) {
max-width: var(--vscode-hover-maxWidth, 500px);
word-wrap: break-word;
}
.monaco-hover .markdown-hover > .hover-contents:not(.code-hover-contents) hr {
min-width: 100%;
}
.monaco-hover p,
.monaco-hover .code,
.monaco-hover ul,
.monaco-hover h1,
.monaco-hover h2,
.monaco-hover h3,
.monaco-hover h4,
.monaco-hover h5,
.monaco-hover h6 {
margin: 8px 0;
}
.monaco-hover h1,
.monaco-hover h2,
.monaco-hover h3,
.monaco-hover h4,
.monaco-hover h5,
.monaco-hover h6 {
line-height: 1.1;
}
.monaco-hover code {
font-family: var(--monaco-monospace-font);
}
.monaco-hover hr {
box-sizing: border-box;
border-left: 0px;
border-right: 0px;
margin-top: 4px;
margin-bottom: -4px;
margin-left: -8px;
margin-right: -8px;
height: 1px;
}
.monaco-hover p:first-child,
.monaco-hover .code:first-child,
.monaco-hover ul:first-child {
margin-top: 0;
}
.monaco-hover p:last-child,
.monaco-hover .code:last-child,
.monaco-hover ul:last-child {
margin-bottom: 0;
}
/* MarkupContent Layout */
.monaco-hover ul {
padding-left: 20px;
}
.monaco-hover ol {
padding-left: 20px;
}
.monaco-hover li > p {
margin-bottom: 0;
}
.monaco-hover li > ul {
margin-top: 0;
}
.monaco-hover code {
border-radius: 3px;
padding: 0 0.4em;
}
.monaco-hover .monaco-tokenized-source {
white-space: var(--vscode-hover-sourceWhiteSpace, pre-wrap);
}
.monaco-hover .hover-row.status-bar {
font-size: 12px;
line-height: 22px;
}
.monaco-hover .hover-row.status-bar .info {
font-style: italic;
padding: 0px 8px;
}
.monaco-hover .hover-row.status-bar .actions {
display: flex;
padding: 0px 8px;
width: 100%;
}
.monaco-hover .hover-row.status-bar .actions .action-container {
margin-right: 16px;
cursor: pointer;
overflow: hidden;
text-wrap: nowrap;
text-overflow: ellipsis;
}
.monaco-hover .hover-row.status-bar .actions .action-container .action .icon {
padding-right: 4px;
vertical-align: middle;
}
.monaco-hover .hover-row.status-bar .actions .action-container a {
color: var(--vscode-textLink-foreground);
text-decoration: var(--text-link-decoration);
}
.monaco-hover .hover-row.status-bar .actions .action-container a .icon.codicon {
color: var(--vscode-textLink-foreground);
}
.monaco-hover .markdown-hover .hover-contents .codicon {
color: inherit;
font-size: inherit;
vertical-align: middle;
}
.monaco-hover .hover-contents a.code-link:hover,
.monaco-hover .hover-contents a.code-link {
color: inherit;
}
.monaco-hover .hover-contents a.code-link:before {
content: '(';
}
.monaco-hover .hover-contents a.code-link:after {
content: ')';
}
.monaco-hover .hover-contents a.code-link > span {
text-decoration: underline;
/** Hack to force underline to show **/
border-bottom: 1px solid transparent;
text-underline-position: under;
color: var(--vscode-textLink-foreground);
}
.monaco-hover .hover-contents a.code-link > span:hover {
color: var(--vscode-textLink-activeForeground);
}
/**
* Spans in markdown hovers need a margin-bottom to avoid looking cramped:
* https://github.com/microsoft/vscode/issues/101496
* This was later refined to only apply when the last child of a rendered markdown block (before the
* border or a `hr`) uses background color:
* https://github.com/microsoft/vscode/issues/228136
*/
.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents):not(.html-hover-contents) p:last-child [style*="background-color"] {
margin-bottom: 4px;
display: inline-block;
}
/**
* Add a slight margin to try vertically align codicons with any text
* https://github.com/microsoft/vscode/issues/221359
*/
.monaco-hover .markdown-hover .hover-contents:not(.code-hover-contents):not(.html-hover-contents) span.codicon {
margin-bottom: 2px;
}
.monaco-hover-content .action-container a {
-webkit-user-select: none;
user-select: none;
}
.monaco-hover-content .action-container.disabled {
pointer-events: none;
opacity: 0.4;
cursor: default;
}
/* Prevent text selection in all button-like elements within hovers */
.monaco-hover .action-container,
.monaco-hover .action,
.monaco-hover button,
.monaco-hover .monaco-button,
.monaco-hover .monaco-text-button,
.monaco-hover [role="button"] {
-webkit-user-select: none;
user-select: none;
}
@@ -0,0 +1,93 @@
import { append, $ as $$1, addDisposableListener, EventType } from '../../dom.js';
import { StandardKeyboardEvent } from '../../keyboardEvent.js';
import { DomScrollableElement } from '../scrollbar/scrollableElement.js';
import { Disposable } from '../../../common/lifecycle.js';
import './hoverWidget.css';
import { localize } from '../../../../nls.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const $ = $$1;
class HoverWidget extends Disposable {
constructor(fadeIn) {
super();
this.containerDomNode = document.createElement('div');
this.containerDomNode.className = 'monaco-hover';
this.containerDomNode.classList.toggle('fade-in', !!fadeIn);
this.containerDomNode.tabIndex = 0;
this.containerDomNode.setAttribute('role', 'tooltip');
this.contentsDomNode = document.createElement('div');
this.contentsDomNode.className = 'monaco-hover-content';
this.scrollbar = this._register(new DomScrollableElement(this.contentsDomNode, {
consumeMouseWheelIfScrollbarIsNeeded: true
}));
this.containerDomNode.appendChild(this.scrollbar.getDomNode());
}
onContentsChanged() {
this.scrollbar.scanDomNode();
}
}
class HoverAction extends Disposable {
static render(parent, actionOptions, keybindingLabel) {
return new HoverAction(parent, actionOptions, keybindingLabel);
}
constructor(parent, actionOptions, keybindingLabel) {
super();
this.actionLabel = actionOptions.label;
this.actionKeybindingLabel = keybindingLabel;
this.actionContainer = append(parent, $('div.action-container'));
this.actionContainer.setAttribute('tabindex', '0');
this.action = append(this.actionContainer, $('a.action'));
this.action.setAttribute('role', 'button');
if (actionOptions.iconClass) {
const iconElement = append(this.action, $(`span.icon`));
iconElement.classList.add(...actionOptions.iconClass.split(' '));
}
this.actionRenderedLabel = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;
const label = append(this.action, $('span'));
label.textContent = this.actionRenderedLabel;
this._store.add(new ClickAction(this.actionContainer, actionOptions.run));
this._store.add(new KeyDownAction(this.actionContainer, actionOptions.run, [3 /* KeyCode.Enter */, 10 /* KeyCode.Space */]));
this.setEnabled(true);
}
setEnabled(enabled) {
if (enabled) {
this.actionContainer.classList.remove('disabled');
this.actionContainer.removeAttribute('aria-disabled');
}
else {
this.actionContainer.classList.add('disabled');
this.actionContainer.setAttribute('aria-disabled', 'true');
}
}
}
function getHoverAccessibleViewHint(shouldHaveHint, keybinding) {
return shouldHaveHint && keybinding ? localize(7, "Inspect this in the accessible view with {0}.", keybinding) : shouldHaveHint ? localize(8, "Inspect this in the accessible view via the command Open Accessible View which is currently not triggerable via keybinding.") : '';
}
class ClickAction extends Disposable {
constructor(container, run) {
super();
this._register(addDisposableListener(container, EventType.CLICK, e => {
e.stopPropagation();
e.preventDefault();
run(container);
}));
}
}
class KeyDownAction extends Disposable {
constructor(container, run, keyCodes) {
super();
this._register(addDisposableListener(container, EventType.KEY_DOWN, e => {
const event = new StandardKeyboardEvent(e);
if (keyCodes.some(keyCode => event.equals(keyCode))) {
e.stopPropagation();
e.preventDefault();
run(container);
}
}));
}
}
export { ClickAction, HoverAction, HoverWidget, KeyDownAction, getHoverAccessibleViewHint };
@@ -0,0 +1,291 @@
import './iconlabel.css';
import { append, $, isHTMLElement, isAncestor, after } from '../../dom.js';
import { asCSSUrl } from '../../cssValue.js';
import { HighlightedLabel } from '../highlightedlabel/highlightedLabel.js';
import { Disposable } from '../../../common/lifecycle.js';
import { equals } from '../../../common/objects.js';
import { Range } from '../../../common/range.js';
import { getDefaultHoverDelegate } from '../hover/hoverDelegateFactory.js';
import { getBaseLayerHoverDelegate } from '../hover/hoverDelegate2.js';
import { ThemeIcon } from '../../../common/themables.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class FastLabelNode {
constructor(_element) {
this._element = _element;
}
get element() {
return this._element;
}
set textContent(content) {
if (this.disposed || content === this._textContent) {
return;
}
this._textContent = content;
this._element.textContent = content;
}
set classNames(classNames) {
if (this.disposed || equals(classNames, this._classNames)) {
return;
}
this._classNames = classNames;
this._element.classList.value = '';
this._element.classList.add(...classNames);
}
set empty(empty) {
if (this.disposed || empty === this._empty) {
return;
}
this._empty = empty;
this._element.style.marginLeft = empty ? '0' : '';
}
dispose() {
this.disposed = true;
}
}
class IconLabel extends Disposable {
constructor(container, options) {
super();
this.customHovers = new Map();
this.creationOptions = options;
this.domNode = this._register(new FastLabelNode(append(container, $('.monaco-icon-label'))));
this.labelContainer = append(this.domNode.element, $('.monaco-icon-label-container'));
this.nameContainer = append(this.labelContainer, $('span.monaco-icon-name-container'));
if (options?.supportHighlights || options?.supportIcons) {
this.nameNode = this._register(new LabelWithHighlights(this.nameContainer, !!options.supportIcons));
}
else {
this.nameNode = new Label(this.nameContainer);
}
this.hoverDelegate = options?.hoverDelegate ?? getDefaultHoverDelegate('mouse');
}
get element() {
return this.domNode.element;
}
setLabel(label, description, options) {
const labelClasses = ['monaco-icon-label'];
const containerClasses = ['monaco-icon-label-container'];
let ariaLabel = '';
if (options) {
if (options.extraClasses) {
labelClasses.push(...options.extraClasses);
}
if (options.bold) {
labelClasses.push('bold');
}
if (options.italic) {
labelClasses.push('italic');
}
if (options.strikethrough) {
labelClasses.push('strikethrough');
}
if (options.disabledCommand) {
containerClasses.push('disabled');
}
if (options.title) {
if (typeof options.title === 'string') {
ariaLabel += options.title;
}
else {
ariaLabel += label;
}
}
}
// eslint-disable-next-line no-restricted-syntax
const existingIconNode = this.domNode.element.querySelector('.monaco-icon-label-iconpath');
if (options?.iconPath) {
let iconNode;
if (!existingIconNode || !(isHTMLElement(existingIconNode))) {
iconNode = $('.monaco-icon-label-iconpath');
this.domNode.element.prepend(iconNode);
}
else {
iconNode = existingIconNode;
}
if (ThemeIcon.isThemeIcon(options.iconPath)) {
const iconClass = ThemeIcon.asClassName(options.iconPath);
iconNode.className = `monaco-icon-label-iconpath ${iconClass}`;
iconNode.style.backgroundImage = '';
}
else {
iconNode.style.backgroundImage = asCSSUrl(options?.iconPath);
}
iconNode.style.backgroundRepeat = 'no-repeat';
iconNode.style.backgroundPosition = 'center';
iconNode.style.backgroundSize = 'contain';
}
else if (existingIconNode) {
existingIconNode.remove();
}
this.domNode.classNames = labelClasses;
this.domNode.element.setAttribute('aria-label', ariaLabel);
this.labelContainer.classList.value = '';
this.labelContainer.classList.add(...containerClasses);
this.setupHover(options?.descriptionTitle ? this.labelContainer : this.element, options?.title);
this.nameNode.setLabel(label, options);
if (description || this.descriptionNode) {
const descriptionNode = this.getOrCreateDescriptionNode();
if (descriptionNode instanceof HighlightedLabel) {
const supportIcons = options?.supportIcons ?? this.creationOptions?.supportIcons;
descriptionNode.set(description || '', options ? options.descriptionMatches : undefined, undefined, options?.labelEscapeNewLines, supportIcons);
this.setupHover(descriptionNode.element, options?.descriptionTitle);
}
else {
descriptionNode.textContent = description && options?.labelEscapeNewLines ? HighlightedLabel.escapeNewLines(description, []) : (description || '');
this.setupHover(descriptionNode.element, options?.descriptionTitle || '');
descriptionNode.empty = !description;
}
}
if (options?.suffix || this.suffixNode) {
const suffixNode = this.getOrCreateSuffixNode();
suffixNode.textContent = options?.suffix ?? '';
}
}
setupHover(htmlElement, tooltip) {
const previousCustomHover = this.customHovers.get(htmlElement);
if (previousCustomHover) {
previousCustomHover.dispose();
this.customHovers.delete(htmlElement);
}
if (!tooltip) {
htmlElement.removeAttribute('title');
return;
}
let hoverTarget = htmlElement;
if (this.creationOptions?.hoverTargetOverride) {
if (!isAncestor(htmlElement, this.creationOptions.hoverTargetOverride)) {
throw new Error('hoverTargetOverrride must be an ancestor of the htmlElement');
}
hoverTarget = this.creationOptions.hoverTargetOverride;
}
const hoverDisposable = getBaseLayerHoverDelegate().setupManagedHover(this.hoverDelegate, hoverTarget, tooltip);
if (hoverDisposable) {
this.customHovers.set(htmlElement, hoverDisposable);
}
}
dispose() {
super.dispose();
for (const disposable of this.customHovers.values()) {
disposable.dispose();
}
this.customHovers.clear();
}
getOrCreateSuffixNode() {
if (!this.suffixNode) {
const suffixContainer = this._register(new FastLabelNode(after(this.nameContainer, $('span.monaco-icon-suffix-container'))));
this.suffixNode = this._register(new FastLabelNode(append(suffixContainer.element, $('span.label-suffix'))));
}
return this.suffixNode;
}
getOrCreateDescriptionNode() {
if (!this.descriptionNode) {
const descriptionContainer = this._register(new FastLabelNode(append(this.labelContainer, $('span.monaco-icon-description-container'))));
if (this.creationOptions?.supportDescriptionHighlights) {
this.descriptionNode = this._register(new HighlightedLabel(append(descriptionContainer.element, $('span.label-description'))));
}
else {
this.descriptionNode = this._register(new FastLabelNode(append(descriptionContainer.element, $('span.label-description'))));
}
}
return this.descriptionNode;
}
}
class Label {
constructor(container) {
this.container = container;
this.label = undefined;
this.singleLabel = undefined;
}
setLabel(label, options) {
if (this.label === label && equals(this.options, options)) {
return;
}
this.label = label;
this.options = options;
if (typeof label === 'string') {
if (!this.singleLabel) {
this.container.textContent = '';
this.container.classList.remove('multiple');
this.singleLabel = append(this.container, $('a.label-name', { id: options?.domId }));
}
this.singleLabel.textContent = label;
}
else {
this.container.textContent = '';
this.container.classList.add('multiple');
this.singleLabel = undefined;
for (let i = 0; i < label.length; i++) {
const l = label[i];
const id = options?.domId && `${options?.domId}_${i}`;
append(this.container, $('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i, 'role': 'treeitem' }, l));
if (i < label.length - 1) {
append(this.container, $('span.label-separator', undefined, options?.separator || '/'));
}
}
}
}
}
function splitMatches(labels, separator, matches) {
if (!matches) {
return undefined;
}
let labelStart = 0;
return labels.map(label => {
const labelRange = { start: labelStart, end: labelStart + label.length };
const result = matches
.map(match => Range.intersect(labelRange, match))
.filter(range => !Range.isEmpty(range))
.map(({ start, end }) => ({ start: start - labelStart, end: end - labelStart }));
labelStart = labelRange.end + separator.length;
return result;
});
}
class LabelWithHighlights extends Disposable {
constructor(container, supportIcons) {
super();
this.container = container;
this.supportIcons = supportIcons;
this.label = undefined;
this.singleLabel = undefined;
}
setLabel(label, options) {
if (this.label === label && equals(this.options, options)) {
return;
}
this.label = label;
this.options = options;
// Determine supportIcons: use option if provided, otherwise use constructor value
const supportIcons = options?.supportIcons ?? this.supportIcons;
if (typeof label === 'string') {
if (!this.singleLabel) {
this.container.textContent = '';
this.container.classList.remove('multiple');
this.singleLabel = this._register(new HighlightedLabel(append(this.container, $('a.label-name', { id: options?.domId }))));
}
this.singleLabel.set(label, options?.matches, undefined, options?.labelEscapeNewLines, supportIcons);
}
else {
this.container.textContent = '';
this.container.classList.add('multiple');
this.singleLabel = undefined;
const separator = options?.separator || '/';
const matches = splitMatches(label, separator, options?.matches);
for (let i = 0; i < label.length; i++) {
const l = label[i];
const m = matches ? matches[i] : undefined;
const id = options?.domId && `${options?.domId}_${i}`;
const name = $('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i, 'role': 'treeitem' });
const highlightedLabel = this._register(new HighlightedLabel(append(this.container, name)));
highlightedLabel.set(l, m, undefined, options?.labelEscapeNewLines, supportIcons);
if (i < label.length - 1) {
append(name, $('span.label-separator', undefined, separator));
}
}
}
}
}
export { IconLabel };
@@ -0,0 +1,33 @@
import { $ } from '../../dom.js';
import { ThemeIcon } from '../../../common/themables.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const labelWithIconsRegex = new RegExp(`(\\\\)?\\$\\((${ThemeIcon.iconNameExpression}(?:${ThemeIcon.iconModifierExpression})?)\\)`, 'g');
function renderLabelWithIcons(text) {
const elements = new Array();
let match;
let textStart = 0, textStop = 0;
while ((match = labelWithIconsRegex.exec(text)) !== null) {
textStop = match.index || 0;
if (textStart < textStop) {
elements.push(text.substring(textStart, textStop));
}
textStart = (match.index || 0) + match[0].length;
const [, escaped, codicon] = match;
elements.push(escaped ? `$(${codicon})` : renderIcon({ id: codicon }));
}
if (textStart < text.length) {
elements.push(text.substring(textStart));
}
return elements;
}
function renderIcon(icon) {
const node = $(`span`);
node.classList.add(...ThemeIcon.asClassNameArray(icon));
return node;
}
export { renderIcon, renderLabelWithIcons };
@@ -0,0 +1,119 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* ---------- Icon label ---------- */
.monaco-icon-label {
display: flex; /* required for icons support :before rule */
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-icon-label::before {
/* svg icons rendered as background image */
background-size: 16px;
background-position: left center;
background-repeat: no-repeat;
padding-right: 6px;
width: 16px;
height: 22px;
line-height: inherit !important;
display: inline-block;
/* fonts icons */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
vertical-align: top;
flex-shrink: 0; /* fix for https://github.com/microsoft/vscode/issues/13787 */
}
.monaco-icon-label-iconpath {
width: 16px;
height: 22px;
margin-right: 6px;
display: flex;
}
.monaco-icon-label-container.disabled {
color: var(--vscode-disabledForeground);
}
.monaco-icon-label > .monaco-icon-label-container {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
}
.monaco-icon-label > .monaco-icon-label-container > .monaco-icon-name-container > .label-name {
color: inherit;
white-space: pre; /* enable to show labels that include multiple whitespaces */
}
.monaco-icon-label > .monaco-icon-label-container > .monaco-icon-name-container > .label-name > .label-separator {
margin: 0 2px;
opacity: 0.5;
}
.monaco-icon-label > .monaco-icon-label-container > .monaco-icon-suffix-container > .label-suffix {
opacity: .7;
white-space: pre;
}
.monaco-icon-label > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
opacity: .7;
margin-left: 0.5em;
font-size: 0.9em;
white-space: pre; /* enable to show labels that include multiple whitespaces */
}
.monaco-icon-label.nowrap > .monaco-icon-label-container > .monaco-icon-description-container > .label-description{
white-space: nowrap
}
.vs .monaco-icon-label > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
opacity: .95;
}
.monaco-icon-label.bold > .monaco-icon-label-container > .monaco-icon-name-container > .label-name,
.monaco-icon-label.bold > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
font-weight: bold;
}
.monaco-icon-label.italic > .monaco-icon-label-container > .monaco-icon-name-container > .label-name,
.monaco-icon-label.italic > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
font-style: italic;
}
.monaco-icon-label.deprecated {
text-decoration: line-through;
opacity: 0.66;
}
.monaco-icon-label.strikethrough > .monaco-icon-label-container > .monaco-icon-name-container > .label-name,
.monaco-icon-label.strikethrough > .monaco-icon-label-container > .monaco-icon-description-container > .label-description {
text-decoration: line-through;
}
.monaco-icon-label::after {
opacity: 0.75;
font-size: 90%;
font-weight: 600;
margin: auto 16px 0 5px; /* https://github.com/microsoft/vscode/issues/113223 */
text-align: center;
}
/* make sure selection color wins when a label is being selected */
.monaco-list:focus .selected .monaco-icon-label, /* list */
.monaco-list:focus .selected .monaco-icon-label::after
{
color: inherit !important;
}
.monaco-list-row.focused.selected .label-description,
.monaco-list-row.selected .label-description {
opacity: .8;
}
@@ -0,0 +1,106 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-inputbox {
position: relative;
display: block;
padding: 0;
box-sizing: border-box;
border-radius: 2px;
/* Customizable */
font-size: inherit;
}
.monaco-inputbox > .ibwrapper > .input,
.monaco-inputbox > .ibwrapper > .mirror {
/* Customizable */
padding: 4px 6px;
}
.monaco-inputbox > .ibwrapper {
position: relative;
width: 100%;
}
.monaco-inputbox > .ibwrapper > .input {
display: inline-block;
box-sizing: border-box;
width: 100%;
height: 100%;
line-height: inherit;
border: none;
font-family: inherit;
font-size: inherit;
resize: none;
color: inherit;
}
.monaco-inputbox > .ibwrapper > input {
text-overflow: ellipsis;
}
.monaco-inputbox > .ibwrapper > textarea.input {
display: block;
scrollbar-width: none; /* Firefox: hide scrollbars */
outline: none;
}
.monaco-inputbox > .ibwrapper > textarea.input::-webkit-scrollbar {
display: none; /* Chrome + Safari: hide scrollbar */
}
.monaco-inputbox > .ibwrapper > textarea.input.empty {
white-space: nowrap;
}
.monaco-inputbox > .ibwrapper > .mirror {
position: absolute;
display: inline-block;
width: 100%;
top: 0;
left: 0;
box-sizing: border-box;
white-space: pre-wrap;
visibility: hidden;
word-wrap: break-word;
}
/* Context view */
.monaco-inputbox-container {
text-align: right;
}
.monaco-inputbox-container .monaco-inputbox-message {
display: inline-block;
overflow: hidden;
text-align: left;
width: 100%;
box-sizing: border-box;
padding: 0.4em;
font-size: 12px;
line-height: 17px;
margin-top: -1px;
word-wrap: break-word;
}
/* Action bar support */
.monaco-inputbox .monaco-action-bar {
position: absolute;
right: 2px;
top: 4px;
}
.monaco-inputbox .monaco-action-bar .action-item {
margin-left: 2px;
}
.monaco-inputbox .monaco-action-bar .action-item .codicon {
background-repeat: no-repeat;
width: 16px;
height: 16px;
}
@@ -0,0 +1,510 @@
import { append, $ as $$1, getTotalHeight, isActiveElement, getTotalWidth } from '../../dom.js';
import { asCssValueWithDefault } from '../../cssValue.js';
import { DomEmitter } from '../../event.js';
import { renderFormattedText, renderText } from '../../formattedTextRenderer.js';
import { ActionBar } from '../actionbar/actionbar.js';
import { status, alert } from '../aria/aria.js';
import { getBaseLayerHoverDelegate } from '../hover/hoverDelegate2.js';
import { ScrollableElement } from '../scrollbar/scrollableElement.js';
import { Widget } from '../widget.js';
import { Emitter, Event } from '../../../common/event.js';
import { HistoryNavigator } from '../../../common/history.js';
import { equals } from '../../../common/objects.js';
import './inputBox.css';
import { localize } from '../../../../nls.js';
import { MutableDisposable } from '../../../common/lifecycle.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const $ = $$1;
class InputBox extends Widget {
get onDidChange() { return this._onDidChange.event; }
get onDidHeightChange() { return this._onDidHeightChange.event; }
constructor(container, contextViewProvider, options) {
super();
this.state = 'idle';
this.maxHeight = Number.POSITIVE_INFINITY;
this.hover = this._register(new MutableDisposable());
this._onDidChange = this._register(new Emitter());
this._onDidHeightChange = this._register(new Emitter());
this.contextViewProvider = contextViewProvider;
this.options = options;
this.message = null;
this.placeholder = this.options.placeholder || '';
this.tooltip = this.options.tooltip ?? (this.placeholder || '');
this.ariaLabel = this.options.ariaLabel || '';
if (this.options.validationOptions) {
this.validation = this.options.validationOptions.validation;
}
this.element = append(container, $('.monaco-inputbox.idle'));
const tagName = this.options.flexibleHeight ? 'textarea' : 'input';
const wrapper = append(this.element, $('.ibwrapper'));
this.input = append(wrapper, $(tagName + '.input.empty'));
this.input.setAttribute('autocorrect', 'off');
this.input.setAttribute('autocapitalize', 'off');
this.input.setAttribute('spellcheck', 'false');
this.onfocus(this.input, () => this.element.classList.add('synthetic-focus'));
this.onblur(this.input, () => this.element.classList.remove('synthetic-focus'));
if (this.options.flexibleHeight) {
this.maxHeight = typeof this.options.flexibleMaxHeight === 'number' ? this.options.flexibleMaxHeight : Number.POSITIVE_INFINITY;
this.mirror = append(wrapper, $('div.mirror'));
this.mirror.innerText = '\u00a0';
this.scrollableElement = new ScrollableElement(this.element, { vertical: 1 /* ScrollbarVisibility.Auto */ });
if (this.options.flexibleWidth) {
this.input.setAttribute('wrap', 'off');
this.mirror.style.whiteSpace = 'pre';
this.mirror.style.wordWrap = 'initial';
}
append(container, this.scrollableElement.getDomNode());
this._register(this.scrollableElement);
// from ScrollableElement to DOM
this._register(this.scrollableElement.onScroll(e => this.input.scrollTop = e.scrollTop));
const onSelectionChange = this._register(new DomEmitter(container.ownerDocument, 'selectionchange'));
const onAnchoredSelectionChange = Event.filter(onSelectionChange.event, () => {
const selection = container.ownerDocument.getSelection();
return selection?.anchorNode === wrapper;
});
// from DOM to ScrollableElement
this._register(onAnchoredSelectionChange(this.updateScrollDimensions, this));
this._register(this.onDidHeightChange(this.updateScrollDimensions, this));
}
else {
this.input.type = this.options.type || 'text';
this.input.setAttribute('wrap', 'off');
}
if (this.ariaLabel) {
this.input.setAttribute('aria-label', this.ariaLabel);
}
if (this.placeholder && !this.options.showPlaceholderOnFocus) {
this.setPlaceHolder(this.placeholder);
}
if (this.tooltip) {
this.setTooltip(this.tooltip);
}
this.oninput(this.input, () => this.onValueChange());
this.onblur(this.input, () => this.onBlur());
this.onfocus(this.input, () => this.onFocus());
this._register(this.ignoreGesture(this.input));
setTimeout(() => this.updateMirror(), 0);
// Support actions
if (this.options.actions) {
this.actionbar = this._register(new ActionBar(this.element));
this.actionbar.push(this.options.actions, { icon: true, label: false });
}
this.applyStyles();
}
onBlur() {
this._hideMessage();
if (this.options.showPlaceholderOnFocus) {
this.input.setAttribute('placeholder', '');
}
}
onFocus() {
this._showMessage();
if (this.options.showPlaceholderOnFocus) {
this.input.setAttribute('placeholder', this.placeholder || '');
}
}
setPlaceHolder(placeHolder) {
this.placeholder = placeHolder;
this.input.setAttribute('placeholder', placeHolder);
}
setTooltip(tooltip) {
this.tooltip = tooltip;
if (!this.hover.value) {
this.hover.value = this._register(getBaseLayerHoverDelegate().setupDelayedHoverAtMouse(this.input, () => ({
content: this.tooltip,
appearance: {
compact: true,
}
})));
}
}
get inputElement() {
return this.input;
}
get value() {
return this.input.value;
}
set value(newValue) {
if (this.input.value !== newValue) {
this.input.value = newValue;
this.onValueChange();
}
}
get height() {
return typeof this.cachedHeight === 'number' ? this.cachedHeight : getTotalHeight(this.element);
}
focus() {
this.input.focus();
}
blur() {
this.input.blur();
}
hasFocus() {
return isActiveElement(this.input);
}
select(range = null) {
this.input.select();
if (range) {
this.input.setSelectionRange(range.start, range.end);
if (range.end === this.input.value.length) {
this.input.scrollLeft = this.input.scrollWidth;
}
}
}
isSelectionAtEnd() {
return this.input.selectionEnd === this.input.value.length && this.input.selectionStart === this.input.selectionEnd;
}
getSelection() {
const selectionStart = this.input.selectionStart;
if (selectionStart === null) {
return null;
}
const selectionEnd = this.input.selectionEnd ?? selectionStart;
return {
start: selectionStart,
end: selectionEnd,
};
}
enable() {
this.input.removeAttribute('disabled');
}
disable() {
this.blur();
this.input.disabled = true;
this._hideMessage();
}
set paddingRight(paddingRight) {
// Set width to avoid hint text overlapping buttons
this.input.style.width = `calc(100% - ${paddingRight}px)`;
if (this.mirror) {
this.mirror.style.paddingRight = paddingRight + 'px';
}
}
updateScrollDimensions() {
if (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number' || !this.scrollableElement) {
return;
}
const scrollHeight = this.cachedContentHeight;
const height = this.cachedHeight;
const scrollTop = this.input.scrollTop;
this.scrollableElement.setScrollDimensions({ scrollHeight, height });
this.scrollableElement.setScrollPosition({ scrollTop });
}
showMessage(message, force) {
if (this.state === 'open' && equals(this.message, message)) {
// Already showing
return;
}
this.message = message;
this.element.classList.remove('idle');
this.element.classList.remove('info');
this.element.classList.remove('warning');
this.element.classList.remove('error');
this.element.classList.add(this.classForType(message.type));
const styles = this.stylesForType(this.message.type);
this.element.style.border = `1px solid ${asCssValueWithDefault(styles.border, 'transparent')}`;
if (this.message.content && (this.hasFocus() || force)) {
this._showMessage();
}
}
hideMessage() {
this.message = null;
this.element.classList.remove('info');
this.element.classList.remove('warning');
this.element.classList.remove('error');
this.element.classList.add('idle');
this._hideMessage();
this.applyStyles();
}
validate() {
let errorMsg = null;
if (this.validation) {
errorMsg = this.validation(this.value);
if (errorMsg) {
this.inputElement.setAttribute('aria-invalid', 'true');
this.showMessage(errorMsg);
}
else if (this.inputElement.hasAttribute('aria-invalid')) {
this.inputElement.removeAttribute('aria-invalid');
this.hideMessage();
}
}
return errorMsg?.type;
}
stylesForType(type) {
const styles = this.options.inputBoxStyles;
switch (type) {
case 1 /* MessageType.INFO */: return { border: styles.inputValidationInfoBorder, background: styles.inputValidationInfoBackground, foreground: styles.inputValidationInfoForeground };
case 2 /* MessageType.WARNING */: return { border: styles.inputValidationWarningBorder, background: styles.inputValidationWarningBackground, foreground: styles.inputValidationWarningForeground };
default: return { border: styles.inputValidationErrorBorder, background: styles.inputValidationErrorBackground, foreground: styles.inputValidationErrorForeground };
}
}
classForType(type) {
switch (type) {
case 1 /* MessageType.INFO */: return 'info';
case 2 /* MessageType.WARNING */: return 'warning';
default: return 'error';
}
}
_showMessage() {
if (!this.contextViewProvider || !this.message) {
return;
}
let div;
const layout = () => div.style.width = getTotalWidth(this.element) + 'px';
this.contextViewProvider.showContextView({
getAnchor: () => this.element,
anchorAlignment: 1 /* AnchorAlignment.RIGHT */,
render: (container) => {
if (!this.message) {
return null;
}
div = append(container, $('.monaco-inputbox-container'));
layout();
const spanElement = $('span.monaco-inputbox-message');
if (this.message.formatContent) {
renderFormattedText(this.message.content, undefined, spanElement);
}
else {
renderText(this.message.content, undefined, spanElement);
}
spanElement.classList.add(this.classForType(this.message.type));
const styles = this.stylesForType(this.message.type);
spanElement.style.backgroundColor = styles.background ?? '';
spanElement.style.color = styles.foreground ?? '';
spanElement.style.border = styles.border ? `1px solid ${styles.border}` : '';
append(div, spanElement);
return null;
},
onHide: () => {
this.state = 'closed';
},
layout: layout
});
// ARIA Support
let alertText;
if (this.message.type === 3 /* MessageType.ERROR */) {
alertText = localize(9, "Error: {0}", this.message.content);
}
else if (this.message.type === 2 /* MessageType.WARNING */) {
alertText = localize(10, "Warning: {0}", this.message.content);
}
else {
alertText = localize(11, "Info: {0}", this.message.content);
}
alert(alertText);
this.state = 'open';
}
_hideMessage() {
if (!this.contextViewProvider) {
return;
}
if (this.state === 'open') {
this.contextViewProvider.hideContextView();
}
this.state = 'idle';
}
onValueChange() {
this._onDidChange.fire(this.value);
this.validate();
this.updateMirror();
this.input.classList.toggle('empty', !this.value);
if (this.state === 'open' && this.contextViewProvider) {
this.contextViewProvider.layout();
}
}
updateMirror() {
if (!this.mirror) {
return;
}
const value = this.value;
const lastCharCode = value.charCodeAt(value.length - 1);
const suffix = lastCharCode === 10 ? ' ' : '';
const mirrorTextContent = (value + suffix)
.replace(/\u000c/g, ''); // Don't measure with the form feed character, which messes up sizing
if (mirrorTextContent) {
this.mirror.textContent = value + suffix;
}
else {
this.mirror.innerText = '\u00a0';
}
this.layout();
}
applyStyles() {
const styles = this.options.inputBoxStyles;
const background = styles.inputBackground ?? '';
const foreground = styles.inputForeground ?? '';
const border = styles.inputBorder ?? '';
this.element.style.backgroundColor = background;
this.element.style.color = foreground;
this.input.style.backgroundColor = 'inherit';
this.input.style.color = foreground;
// there's always a border, even if the color is not set.
this.element.style.border = `1px solid ${asCssValueWithDefault(border, 'transparent')}`;
}
layout() {
if (!this.mirror) {
return;
}
const previousHeight = this.cachedContentHeight;
this.cachedContentHeight = getTotalHeight(this.mirror);
if (previousHeight !== this.cachedContentHeight) {
this.cachedHeight = Math.min(this.cachedContentHeight, this.maxHeight);
this.input.style.height = this.cachedHeight + 'px';
this._onDidHeightChange.fire(this.cachedContentHeight);
}
}
insertAtCursor(text) {
const inputElement = this.inputElement;
const start = inputElement.selectionStart;
const end = inputElement.selectionEnd;
const content = inputElement.value;
if (start !== null && end !== null) {
this.value = content.substr(0, start) + text + content.substr(end);
inputElement.setSelectionRange(start + 1, start + 1);
this.layout();
}
}
dispose() {
this._hideMessage();
this.message = null;
this.actionbar?.dispose();
super.dispose();
}
}
class HistoryInputBox extends InputBox {
constructor(container, contextViewProvider, options) {
const NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_NO_PARENS = localize(12, ' or {0} for history', `\u21C5`);
const NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS = localize(13, ' ({0} for history)', `\u21C5`);
super(container, contextViewProvider, options);
this._onDidFocus = this._register(new Emitter());
this.onDidFocus = this._onDidFocus.event;
this._onDidBlur = this._register(new Emitter());
this.onDidBlur = this._onDidBlur.event;
this.history = this._register(new HistoryNavigator(options.history, 100));
// Function to append the history suffix to the placeholder if necessary
const addSuffix = () => {
if (options.showHistoryHint && options.showHistoryHint() && !this.placeholder.endsWith(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_NO_PARENS) && !this.placeholder.endsWith(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS) && this.history.getHistory().length) {
const suffix = this.placeholder.endsWith(')') ? NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_NO_PARENS : NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS;
const suffixedPlaceholder = this.placeholder + suffix;
if (options.showPlaceholderOnFocus && !isActiveElement(this.input)) {
this.placeholder = suffixedPlaceholder;
}
else {
this.setPlaceHolder(suffixedPlaceholder);
}
}
};
// Spot the change to the textarea class attribute which occurs when it changes between non-empty and empty,
// and add the history suffix to the placeholder if not yet present
this.observer = new MutationObserver((mutationList, observer) => {
mutationList.forEach((mutation) => {
if (!mutation.target.textContent) {
addSuffix();
}
});
});
this.observer.observe(this.input, { attributeFilter: ['class'] });
this.onfocus(this.input, () => addSuffix());
this.onblur(this.input, () => {
const resetPlaceholder = (historyHint) => {
if (!this.placeholder.endsWith(historyHint)) {
return false;
}
else {
const revertedPlaceholder = this.placeholder.slice(0, this.placeholder.length - historyHint.length);
if (options.showPlaceholderOnFocus) {
this.placeholder = revertedPlaceholder;
}
else {
this.setPlaceHolder(revertedPlaceholder);
}
return true;
}
};
if (!resetPlaceholder(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS)) {
resetPlaceholder(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_NO_PARENS);
}
});
}
dispose() {
super.dispose();
if (this.observer) {
this.observer.disconnect();
this.observer = undefined;
}
}
addToHistory(always) {
if (this.value && (always || this.value !== this.getCurrentValue())) {
this.history.add(this.value);
}
}
isAtLastInHistory() {
return this.history.isLast();
}
isNowhereInHistory() {
return this.history.isNowhere();
}
showNextValue() {
if (!this.history.has(this.value)) {
this.addToHistory();
}
let next = this.getNextValue();
if (next) {
next = next === this.value ? this.getNextValue() : next;
}
this.value = next ?? '';
status(this.value ? this.value : localize(14, "Cleared Input"));
}
showPreviousValue() {
if (!this.history.has(this.value)) {
this.addToHistory();
}
let previous = this.getPreviousValue();
if (previous) {
previous = previous === this.value ? this.getPreviousValue() : previous;
}
if (previous) {
this.value = previous;
status(this.value);
}
}
setPlaceHolder(placeHolder) {
super.setPlaceHolder(placeHolder);
this.setTooltip(placeHolder);
}
onBlur() {
super.onBlur();
this._onDidBlur.fire();
}
onFocus() {
super.onFocus();
this._onDidFocus.fire();
}
getCurrentValue() {
let currentValue = this.history.current();
if (!currentValue) {
currentValue = this.history.last();
this.history.next();
}
return currentValue;
}
getPreviousValue() {
return this.history.previous() || this.history.first();
}
getNextValue() {
return this.history.next();
}
}
export { HistoryInputBox, InputBox };
@@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-keybinding {
display: flex;
align-items: center;
line-height: 10px;
}
.monaco-keybinding > .monaco-keybinding-key {
display: inline-block;
border-style: solid;
border-width: 1px;
border-radius: 3px;
vertical-align: middle;
font-size: 11px;
padding: 3px 5px;
margin: 0 2px;
}
.monaco-keybinding > .monaco-keybinding-key:first-child {
margin-left: 0;
}
.monaco-keybinding > .monaco-keybinding-key:last-child {
margin-right: 0;
}
.monaco-keybinding > .monaco-keybinding-key-separator {
display: inline-block;
}
.monaco-keybinding > .monaco-keybinding-key-chord-separator {
width: 6px;
}
@@ -0,0 +1,122 @@
import { append, $ as $$1, clearNode } from '../../dom.js';
import { getBaseLayerHoverDelegate } from '../hover/hoverDelegate2.js';
import { getDefaultHoverDelegate } from '../hover/hoverDelegateFactory.js';
import { UILabelProvider } from '../../../common/keybindingLabels.js';
import { Disposable } from '../../../common/lifecycle.js';
import { equals } from '../../../common/objects.js';
import './keybindingLabel.css';
import { localize } from '../../../../nls.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const $ = $$1;
const unthemedKeybindingLabelOptions = {
keybindingLabelBackground: undefined,
keybindingLabelForeground: undefined,
keybindingLabelBorder: undefined,
keybindingLabelBottomBorder: undefined,
keybindingLabelShadow: undefined
};
class KeybindingLabel extends Disposable {
constructor(container, os, options) {
super();
this.os = os;
this.keyElements = new Set();
this.options = options || Object.create(null);
const labelForeground = this.options.keybindingLabelForeground;
this.domNode = append(container, $('.monaco-keybinding'));
if (labelForeground) {
this.domNode.style.color = labelForeground;
}
this.hover = this._register(getBaseLayerHoverDelegate().setupManagedHover(getDefaultHoverDelegate('mouse'), this.domNode, ''));
this.didEverRender = false;
container.appendChild(this.domNode);
}
set(keybinding, matches) {
if (this.didEverRender && this.keybinding === keybinding && KeybindingLabel.areSame(this.matches, matches)) {
return;
}
this.keybinding = keybinding;
this.matches = matches;
this.render();
}
render() {
this.clear();
if (this.keybinding) {
const chords = this.keybinding.getChords();
if (chords[0]) {
this.renderChord(this.domNode, chords[0], this.matches ? this.matches.firstPart : null);
}
for (let i = 1; i < chords.length; i++) {
append(this.domNode, $('span.monaco-keybinding-key-chord-separator', undefined, ' '));
this.renderChord(this.domNode, chords[i], this.matches ? this.matches.chordPart : null);
}
const title = (this.options.disableTitle ?? false) ? undefined : this.keybinding.getAriaLabel() || undefined;
this.hover.update(title);
this.domNode.setAttribute('aria-label', title || '');
}
else if (this.options && this.options.renderUnboundKeybindings) {
this.renderUnbound(this.domNode);
}
this.didEverRender = true;
}
clear() {
clearNode(this.domNode);
this.keyElements.clear();
}
renderChord(parent, chord, match) {
const modifierLabels = UILabelProvider.modifierLabels[this.os];
if (chord.ctrlKey) {
this.renderKey(parent, modifierLabels.ctrlKey, Boolean(match?.ctrlKey), modifierLabels.separator);
}
if (chord.shiftKey) {
this.renderKey(parent, modifierLabels.shiftKey, Boolean(match?.shiftKey), modifierLabels.separator);
}
if (chord.altKey) {
this.renderKey(parent, modifierLabels.altKey, Boolean(match?.altKey), modifierLabels.separator);
}
if (chord.metaKey) {
this.renderKey(parent, modifierLabels.metaKey, Boolean(match?.metaKey), modifierLabels.separator);
}
const keyLabel = chord.keyLabel;
if (keyLabel) {
this.renderKey(parent, keyLabel, Boolean(match?.keyCode), '');
}
}
renderKey(parent, label, highlight, separator) {
append(parent, this.createKeyElement(label, highlight ? '.highlight' : ''));
if (separator) {
append(parent, $('span.monaco-keybinding-key-separator', undefined, separator));
}
}
renderUnbound(parent) {
append(parent, this.createKeyElement(localize(15, "Unbound")));
}
createKeyElement(label, extraClass = '') {
const keyElement = $('span.monaco-keybinding-key' + extraClass, undefined, label);
this.keyElements.add(keyElement);
if (this.options.keybindingLabelBackground) {
keyElement.style.backgroundColor = this.options.keybindingLabelBackground;
}
if (this.options.keybindingLabelBorder) {
keyElement.style.borderColor = this.options.keybindingLabelBorder;
}
if (this.options.keybindingLabelBottomBorder) {
keyElement.style.borderBottomColor = this.options.keybindingLabelBottomBorder;
}
if (this.options.keybindingLabelShadow) {
keyElement.style.boxShadow = `inset 0 -1px 0 ${this.options.keybindingLabelShadow}`;
}
return keyElement;
}
static areSame(a, b) {
if (a === b || (!a && !b)) {
return true;
}
return !!a && !!b && equals(a.firstPart, b.firstPart) && equals(a.chordPart, b.chordPart);
}
}
export { KeybindingLabel, unthemedKeybindingLabelOptions };
@@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-list {
position: relative;
height: 100%;
width: 100%;
white-space: nowrap;
}
.monaco-list.mouse-support {
user-select: none;
-webkit-user-select: none;
}
.monaco-list > .monaco-scrollable-element {
height: 100%;
}
.monaco-list-rows {
position: relative;
width: 100%;
height: 100%;
}
.monaco-list.horizontal-scrolling .monaco-list-rows {
width: auto;
min-width: 100%;
}
.monaco-list-row {
position: absolute;
box-sizing: border-box;
overflow: hidden;
width: 100%;
}
.monaco-list.mouse-support .monaco-list-row {
cursor: pointer;
touch-action: none;
}
/* Make sure the scrollbar renders above overlays (sticky scroll) */
.monaco-list .monaco-scrollable-element > .scrollbar.vertical,
.monaco-pane-view > .monaco-split-view2.vertical > .monaco-scrollable-element > .scrollbar.vertical {
z-index: 14;
}
/* for OS X ballistic scrolling */
.monaco-list-row.scrolling {
display: none !important;
}
/* Focus */
.monaco-list.element-focused,
.monaco-list.selection-single,
.monaco-list.selection-multiple {
outline: 0 !important;
}
/* Filter */
.monaco-list-type-filter-message {
position: absolute;
box-sizing: border-box;
width: 100%;
height: 100%;
top: 0;
left: 0;
padding: 40px 1em 1em 1em;
text-align: center;
white-space: normal;
opacity: 0.7;
pointer-events: none;
}
.monaco-list-type-filter-message:empty {
display: none;
}
@@ -0,0 +1,11 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class ListError extends Error {
constructor(user, message) {
super(`ListError [${user}] ${message}`);
}
}
export { ListError };
@@ -0,0 +1,128 @@
import { range } from '../../../common/arrays.js';
import { CancellationTokenSource } from '../../../common/cancellation.js';
import { Event } from '../../../common/event.js';
import { DisposableStore, Disposable } from '../../../common/lifecycle.js';
import './list.css';
import { List } from './listWidget.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class PagedRenderer {
get templateId() { return this.renderer.templateId; }
constructor(renderer, modelProvider) {
this.renderer = renderer;
this.modelProvider = modelProvider;
}
renderTemplate(container) {
const data = this.renderer.renderTemplate(container);
return { data, disposable: Disposable.None };
}
renderElement(index, _, data, details) {
data.disposable?.dispose();
if (!data.data) {
return;
}
const model = this.modelProvider();
if (model.isResolved(index)) {
return this.renderer.renderElement(model.get(index), index, data.data, details);
}
const cts = new CancellationTokenSource();
const promise = model.resolve(index, cts.token);
data.disposable = { dispose: () => cts.cancel() };
this.renderer.renderPlaceholder(index, data.data);
promise.then(entry => this.renderer.renderElement(entry, index, data.data, details));
}
disposeTemplate(data) {
if (data.disposable) {
data.disposable.dispose();
data.disposable = undefined;
}
if (data.data) {
this.renderer.disposeTemplate(data.data);
data.data = undefined;
}
}
}
class PagedAccessibilityProvider {
constructor(modelProvider, accessibilityProvider) {
this.modelProvider = modelProvider;
this.accessibilityProvider = accessibilityProvider;
}
getWidgetAriaLabel() {
return this.accessibilityProvider.getWidgetAriaLabel();
}
getAriaLabel(index) {
const model = this.modelProvider();
if (!model.isResolved(index)) {
return null;
}
return this.accessibilityProvider.getAriaLabel(model.get(index));
}
}
function fromPagedListOptions(modelProvider, options) {
return {
...options,
accessibilityProvider: options.accessibilityProvider && new PagedAccessibilityProvider(modelProvider, options.accessibilityProvider)
};
}
class PagedList {
constructor(user, container, virtualDelegate, renderers, options = {}) {
this.modelDisposables = new DisposableStore();
const modelProvider = () => this.model;
const pagedRenderers = renderers.map(r => new PagedRenderer(r, modelProvider));
this.list = new List(user, container, virtualDelegate, pagedRenderers, fromPagedListOptions(modelProvider, options));
}
updateOptions(options) {
this.list.updateOptions(options);
}
getHTMLElement() {
return this.list.getHTMLElement();
}
get onDidFocus() {
return this.list.onDidFocus;
}
get widget() {
return this.list;
}
get onDidDispose() {
return this.list.onDidDispose;
}
get onMouseDblClick() {
return Event.map(this.list.onMouseDblClick, ({ element, index, browserEvent }) => ({ element: element === undefined ? undefined : this._model.get(element), index, browserEvent }));
}
get onPointer() {
return Event.map(this.list.onPointer, ({ element, index, browserEvent }) => ({ element: element === undefined ? undefined : this._model.get(element), index, browserEvent }));
}
get onDidChangeSelection() {
return Event.map(this.list.onDidChangeSelection, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, browserEvent }));
}
get model() {
return this._model;
}
set model(model) {
this.modelDisposables.clear();
this._model = model;
this.list.splice(0, this.list.length, range(model.length));
this.modelDisposables.add(model.onDidIncrementLength(newLength => this.list.splice(this.list.length, 0, range(this.list.length, newLength))));
}
getFocus() {
return this.list.getFocus();
}
getSelection() {
return this.list.getSelection();
}
getSelectedElements() {
return this.getSelection().map(i => this.model.get(i));
}
style(styles) {
this.list.style(styles);
}
dispose() {
this.list.dispose();
this.modelDisposables.dispose();
}
}
export { PagedList };
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,161 @@
import { Range } from '../../../common/range.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Returns the intersection between a ranged group and a range.
* Returns `[]` if the intersection is empty.
*/
function groupIntersect(range, groups) {
const result = [];
for (const r of groups) {
if (range.start >= r.range.end) {
continue;
}
if (range.end < r.range.start) {
break;
}
const intersection = Range.intersect(range, r.range);
if (Range.isEmpty(intersection)) {
continue;
}
result.push({
range: intersection,
size: r.size
});
}
return result;
}
/**
* Shifts a range by that `much`.
*/
function shift({ start, end }, much) {
return { start: start + much, end: end + much };
}
/**
* Consolidates a collection of ranged groups.
*
* Consolidation is the process of merging consecutive ranged groups
* that share the same `size`.
*/
function consolidate(groups) {
const result = [];
let previousGroup = null;
for (const group of groups) {
const start = group.range.start;
const end = group.range.end;
const size = group.size;
if (previousGroup && size === previousGroup.size) {
previousGroup.range.end = end;
continue;
}
previousGroup = { range: { start, end }, size };
result.push(previousGroup);
}
return result;
}
/**
* Concatenates several collections of ranged groups into a single
* collection.
*/
function concat(...groups) {
return consolidate(groups.reduce((r, g) => r.concat(g), []));
}
class RangeMap {
get paddingTop() {
return this._paddingTop;
}
set paddingTop(paddingTop) {
this._size = this._size + paddingTop - this._paddingTop;
this._paddingTop = paddingTop;
}
constructor(topPadding) {
this.groups = [];
this._size = 0;
this._paddingTop = 0;
this._paddingTop = topPadding ?? 0;
this._size = this._paddingTop;
}
splice(index, deleteCount, items = []) {
const diff = items.length - deleteCount;
const before = groupIntersect({ start: 0, end: index }, this.groups);
const after = groupIntersect({ start: index + deleteCount, end: Number.POSITIVE_INFINITY }, this.groups)
.map(g => ({ range: shift(g.range, diff), size: g.size }));
const middle = items.map((item, i) => ({
range: { start: index + i, end: index + i + 1 },
size: item.size
}));
this.groups = concat(before, middle, after);
this._size = this._paddingTop + this.groups.reduce((t, g) => t + (g.size * (g.range.end - g.range.start)), 0);
}
/**
* Returns the number of items in the range map.
*/
get count() {
const len = this.groups.length;
if (!len) {
return 0;
}
return this.groups[len - 1].range.end;
}
/**
* Returns the sum of the sizes of all items in the range map.
*/
get size() {
return this._size;
}
/**
* Returns the index of the item at the given position.
*/
indexAt(position) {
if (position < 0) {
return -1;
}
if (position < this._paddingTop) {
return 0;
}
let index = 0;
let size = this._paddingTop;
for (const group of this.groups) {
const count = group.range.end - group.range.start;
const newSize = size + (count * group.size);
if (position < newSize) {
return index + Math.floor((position - size) / group.size);
}
index += count;
size = newSize;
}
return index;
}
/**
* Returns the index of the item right after the item at the
* index of the given position.
*/
indexAfter(position) {
return Math.min(this.indexAt(position) + 1, this.count);
}
/**
* Returns the start position of the item at the given index.
*/
positionAt(index) {
if (index < 0) {
return -1;
}
let position = 0;
let count = 0;
for (const group of this.groups) {
const groupCount = group.range.end - group.range.start;
const newCount = count + groupCount;
if (index < newCount) {
return this._paddingTop + position + ((index - count) * group.size);
}
position += groupCount * group.size;
count = newCount;
}
return -1;
}
}
export { RangeMap, consolidate, groupIntersect, shift };
@@ -0,0 +1,110 @@
import { $ } from '../../dom.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class RowCache {
constructor(renderers) {
this.renderers = renderers;
this.cache = new Map();
this.transactionNodesPendingRemoval = new Set();
this.inTransaction = false;
}
/**
* Returns a row either by creating a new one or reusing
* a previously released row which shares the same templateId.
*
* @returns A row and `isReusingConnectedDomNode` if the row's node is already in the dom in a stale position.
*/
alloc(templateId) {
let result = this.getTemplateCache(templateId).pop();
let isStale = false;
if (result) {
isStale = this.transactionNodesPendingRemoval.has(result.domNode);
if (isStale) {
this.transactionNodesPendingRemoval.delete(result.domNode);
}
}
else {
const domNode = $('.monaco-list-row');
const renderer = this.getRenderer(templateId);
const templateData = renderer.renderTemplate(domNode);
result = { domNode, templateId, templateData };
}
return { row: result, isReusingConnectedDomNode: isStale };
}
/**
* Releases the row for eventual reuse.
*/
release(row) {
if (!row) {
return;
}
this.releaseRow(row);
}
/**
* Begin a set of changes that use the cache. This lets us skip work when a row is removed and then inserted again.
*/
transact(makeChanges) {
if (this.inTransaction) {
throw new Error('Already in transaction');
}
this.inTransaction = true;
try {
makeChanges();
}
finally {
for (const domNode of this.transactionNodesPendingRemoval) {
this.doRemoveNode(domNode);
}
this.transactionNodesPendingRemoval.clear();
this.inTransaction = false;
}
}
releaseRow(row) {
const { domNode, templateId } = row;
if (domNode) {
if (this.inTransaction) {
this.transactionNodesPendingRemoval.add(domNode);
}
else {
this.doRemoveNode(domNode);
}
}
const cache = this.getTemplateCache(templateId);
cache.push(row);
}
doRemoveNode(domNode) {
domNode.classList.remove('scrolling');
domNode.remove();
}
getTemplateCache(templateId) {
let result = this.cache.get(templateId);
if (!result) {
result = [];
this.cache.set(templateId, result);
}
return result;
}
dispose() {
this.cache.forEach((cachedRows, templateId) => {
for (const cachedRow of cachedRows) {
const renderer = this.getRenderer(templateId);
renderer.disposeTemplate(cachedRow.templateData);
cachedRow.templateData = null;
}
});
this.cache.clear();
this.transactionNodesPendingRemoval.clear();
}
getRenderer(templateId) {
const renderer = this.renderers.get(templateId);
if (!renderer) {
throw new Error(`No renderer found for ${templateId}`);
}
return renderer;
}
}
export { RowCache };
@@ -0,0 +1,14 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class CombinedSpliceable {
constructor(spliceables) {
this.spliceables = spliceables;
}
splice(start, deleteCount, elements) {
this.spliceables.forEach(s => s.splice(start, deleteCount, elements));
}
}
export { CombinedSpliceable };
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-mouse-cursor-text {
cursor: text;
}
@@ -0,0 +1,9 @@
import './mouseCursor.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const MOUSE_CURSOR_TEXT_CSS_CLASS_NAME = `monaco-mouse-cursor-text`;
export { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME };
@@ -0,0 +1,61 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-progress-container {
width: 100%;
height: 2px;
overflow: hidden; /* keep progress bit in bounds */
}
.monaco-progress-container .progress-bit {
width: 2%;
height: 2px;
position: absolute;
left: 0;
display: none;
}
.monaco-progress-container.active .progress-bit {
display: inherit;
}
.monaco-progress-container.discrete .progress-bit {
left: 0;
transition: width 100ms linear;
}
.monaco-progress-container.discrete.done .progress-bit {
width: 100%;
}
.monaco-progress-container.infinite .progress-bit {
animation-name: progress;
animation-duration: 4s;
animation-iteration-count: infinite;
transform: translate3d(0px, 0px, 0px);
animation-timing-function: linear;
}
.monaco-progress-container.infinite.infinite-long-running .progress-bit {
/*
The more smooth `linear` timing function can cause
higher GPU consumption as indicated in
https://github.com/microsoft/vscode/issues/97900 &
https://github.com/microsoft/vscode/issues/138396
*/
animation-timing-function: steps(100);
}
/**
* The progress bit has a width: 2% (1/50) of the parent container. The animation moves it from 0% to 100% of
* that container. Since translateX is relative to the progress bit size, we have to multiple it with
* its relative size to the parent container:
* parent width: 5000%
* bit width: 100%
* translateX should be as follow:
* 50%: 5000% * 50% - 50% (set to center) = 2450%
* 100%: 5000% * 100% - 100% (do not overflow) = 4900%
*/
@keyframes progress { from { transform: translateX(0%) scaleX(1) } 50% { transform: translateX(2500%) scaleX(3) } to { transform: translateX(4900%) scaleX(1) } }
@@ -0,0 +1,105 @@
import { show } from '../../dom.js';
import { RunOnceScheduler } from '../../../common/async.js';
import { Disposable, MutableDisposable } from '../../../common/lifecycle.js';
import './progressbar.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const CSS_DONE = 'done';
const CSS_ACTIVE = 'active';
const CSS_INFINITE = 'infinite';
const CSS_INFINITE_LONG_RUNNING = 'infinite-long-running';
const CSS_DISCRETE = 'discrete';
/**
* A progress bar with support for infinite or discrete progress.
*/
class ProgressBar extends Disposable {
/**
* After a certain time of showing the progress bar, switch
* to long-running mode and throttle animations to reduce
* the pressure on the GPU process.
*
* https://github.com/microsoft/vscode/issues/97900
* https://github.com/microsoft/vscode/issues/138396
*/
static { this.LONG_RUNNING_INFINITE_THRESHOLD = 10000; }
constructor(container, options) {
super();
this.progressSignal = this._register(new MutableDisposable());
this.workedVal = 0;
this.showDelayedScheduler = this._register(new RunOnceScheduler(() => show(this.element), 0));
this.longRunningScheduler = this._register(new RunOnceScheduler(() => this.infiniteLongRunning(), ProgressBar.LONG_RUNNING_INFINITE_THRESHOLD));
this.create(container, options);
}
create(container, options) {
this.element = document.createElement('div');
this.element.classList.add('monaco-progress-container');
this.element.setAttribute('role', 'progressbar');
this.element.setAttribute('aria-valuemin', '0');
container.appendChild(this.element);
this.bit = document.createElement('div');
this.bit.classList.add('progress-bit');
this.bit.style.backgroundColor = options?.progressBarBackground || '#0E70C0';
this.element.appendChild(this.bit);
}
off() {
this.bit.style.width = 'inherit';
this.bit.style.opacity = '1';
this.element.classList.remove(CSS_ACTIVE, CSS_INFINITE, CSS_INFINITE_LONG_RUNNING, CSS_DISCRETE);
this.workedVal = 0;
this.totalWork = undefined;
this.longRunningScheduler.cancel();
this.progressSignal.clear();
}
/**
* Stops the progressbar from showing any progress instantly without fading out.
*/
stop() {
return this.doDone(false);
}
doDone(delayed) {
this.element.classList.add(CSS_DONE);
// discrete: let it grow to 100% width and hide afterwards
if (!this.element.classList.contains(CSS_INFINITE)) {
this.bit.style.width = 'inherit';
if (delayed) {
setTimeout(() => this.off(), 200);
}
else {
this.off();
}
}
// infinite: let it fade out and hide afterwards
else {
this.bit.style.opacity = '0';
if (delayed) {
setTimeout(() => this.off(), 200);
}
else {
this.off();
}
}
return this;
}
/**
* Use this mode to indicate progress that has no total number of work units.
*/
infinite() {
this.bit.style.width = '2%';
this.bit.style.opacity = '1';
this.element.classList.remove(CSS_DISCRETE, CSS_DONE, CSS_INFINITE_LONG_RUNNING);
this.element.classList.add(CSS_ACTIVE, CSS_INFINITE);
this.longRunningScheduler.schedule();
return this;
}
infiniteLongRunning() {
this.element.classList.add(CSS_INFINITE_LONG_RUNNING);
}
getContainer() {
return this.element;
}
}
export { ProgressBar };
@@ -0,0 +1,150 @@
import { Dimension } from '../../dom.js';
import { Sash, OrthogonalEdge } from '../sash/sash.js';
import { Emitter, Event } from '../../../common/event.js';
import { DisposableStore } from '../../../common/lifecycle.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class ResizableHTMLElement {
get onDidWillResize() { return this._onDidWillResize.event; }
get onDidResize() { return this._onDidResize.event; }
constructor() {
this._onDidWillResize = new Emitter();
this._onDidResize = new Emitter();
this._sashListener = new DisposableStore();
this._size = new Dimension(0, 0);
this._minSize = new Dimension(0, 0);
this._maxSize = new Dimension(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
this.domNode = document.createElement('div');
this._eastSash = new Sash(this.domNode, { getVerticalSashLeft: () => this._size.width }, { orientation: 0 /* Orientation.VERTICAL */ });
this._westSash = new Sash(this.domNode, { getVerticalSashLeft: () => 0 }, { orientation: 0 /* Orientation.VERTICAL */ });
this._northSash = new Sash(this.domNode, { getHorizontalSashTop: () => 0 }, { orientation: 1 /* Orientation.HORIZONTAL */, orthogonalEdge: OrthogonalEdge.North });
this._southSash = new Sash(this.domNode, { getHorizontalSashTop: () => this._size.height }, { orientation: 1 /* Orientation.HORIZONTAL */, orthogonalEdge: OrthogonalEdge.South });
this._northSash.orthogonalStartSash = this._westSash;
this._northSash.orthogonalEndSash = this._eastSash;
this._southSash.orthogonalStartSash = this._westSash;
this._southSash.orthogonalEndSash = this._eastSash;
let currentSize;
let deltaY = 0;
let deltaX = 0;
this._sashListener.add(Event.any(this._northSash.onDidStart, this._eastSash.onDidStart, this._southSash.onDidStart, this._westSash.onDidStart)(() => {
if (currentSize === undefined) {
this._onDidWillResize.fire();
currentSize = this._size;
deltaY = 0;
deltaX = 0;
}
}));
this._sashListener.add(Event.any(this._northSash.onDidEnd, this._eastSash.onDidEnd, this._southSash.onDidEnd, this._westSash.onDidEnd)(() => {
if (currentSize !== undefined) {
currentSize = undefined;
deltaY = 0;
deltaX = 0;
this._onDidResize.fire({ dimension: this._size, done: true });
}
}));
this._sashListener.add(this._eastSash.onDidChange(e => {
if (currentSize) {
deltaX = e.currentX - e.startX;
this.layout(currentSize.height + deltaY, currentSize.width + deltaX);
this._onDidResize.fire({ dimension: this._size, done: false, east: true });
}
}));
this._sashListener.add(this._westSash.onDidChange(e => {
if (currentSize) {
deltaX = -(e.currentX - e.startX);
this.layout(currentSize.height + deltaY, currentSize.width + deltaX);
this._onDidResize.fire({ dimension: this._size, done: false, west: true });
}
}));
this._sashListener.add(this._northSash.onDidChange(e => {
if (currentSize) {
deltaY = -(e.currentY - e.startY);
this.layout(currentSize.height + deltaY, currentSize.width + deltaX);
this._onDidResize.fire({ dimension: this._size, done: false, north: true });
}
}));
this._sashListener.add(this._southSash.onDidChange(e => {
if (currentSize) {
deltaY = e.currentY - e.startY;
this.layout(currentSize.height + deltaY, currentSize.width + deltaX);
this._onDidResize.fire({ dimension: this._size, done: false, south: true });
}
}));
this._sashListener.add(Event.any(this._eastSash.onDidReset, this._westSash.onDidReset)(e => {
if (this._preferredSize) {
this.layout(this._size.height, this._preferredSize.width);
this._onDidResize.fire({ dimension: this._size, done: true });
}
}));
this._sashListener.add(Event.any(this._northSash.onDidReset, this._southSash.onDidReset)(e => {
if (this._preferredSize) {
this.layout(this._preferredSize.height, this._size.width);
this._onDidResize.fire({ dimension: this._size, done: true });
}
}));
}
dispose() {
this._northSash.dispose();
this._southSash.dispose();
this._eastSash.dispose();
this._westSash.dispose();
this._sashListener.dispose();
this._onDidResize.dispose();
this._onDidWillResize.dispose();
this.domNode.remove();
}
enableSashes(north, east, south, west) {
this._northSash.state = north ? 3 /* SashState.Enabled */ : 0 /* SashState.Disabled */;
this._eastSash.state = east ? 3 /* SashState.Enabled */ : 0 /* SashState.Disabled */;
this._southSash.state = south ? 3 /* SashState.Enabled */ : 0 /* SashState.Disabled */;
this._westSash.state = west ? 3 /* SashState.Enabled */ : 0 /* SashState.Disabled */;
}
layout(height = this.size.height, width = this.size.width) {
const { height: minHeight, width: minWidth } = this._minSize;
const { height: maxHeight, width: maxWidth } = this._maxSize;
height = Math.max(minHeight, Math.min(maxHeight, height));
width = Math.max(minWidth, Math.min(maxWidth, width));
const newSize = new Dimension(width, height);
if (!Dimension.equals(newSize, this._size)) {
this.domNode.style.height = height + 'px';
this.domNode.style.width = width + 'px';
this._size = newSize;
this._northSash.layout();
this._eastSash.layout();
this._southSash.layout();
this._westSash.layout();
}
}
clearSashHoverState() {
this._eastSash.clearSashHoverState();
this._westSash.clearSashHoverState();
this._northSash.clearSashHoverState();
this._southSash.clearSashHoverState();
}
get size() {
return this._size;
}
set maxSize(value) {
this._maxSize = value;
}
get maxSize() {
return this._maxSize;
}
set minSize(value) {
this._minSize = value;
}
get minSize() {
return this._minSize;
}
set preferredSize(value) {
this._preferredSize = value;
}
get preferredSize() {
return this._preferredSize;
}
}
export { ResizableHTMLElement };
@@ -0,0 +1,149 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
:root {
--vscode-sash-size: 4px;
--vscode-sash-hover-size: 4px;
}
.monaco-sash {
position: absolute;
z-index: 35;
touch-action: none;
}
.monaco-sash.disabled {
pointer-events: none;
}
.monaco-sash.mac.vertical {
cursor: col-resize;
}
.monaco-sash.vertical.minimum {
cursor: e-resize;
}
.monaco-sash.vertical.maximum {
cursor: w-resize;
}
.monaco-sash.mac.horizontal {
cursor: row-resize;
}
.monaco-sash.horizontal.minimum {
cursor: s-resize;
}
.monaco-sash.horizontal.maximum {
cursor: n-resize;
}
.monaco-sash.disabled {
cursor: default !important;
pointer-events: none !important;
}
.monaco-sash.vertical {
cursor: ew-resize;
top: 0;
width: var(--vscode-sash-size);
height: 100%;
}
.monaco-sash.horizontal {
cursor: ns-resize;
left: 0;
width: 100%;
height: var(--vscode-sash-size);
}
.monaco-sash:not(.disabled) > .orthogonal-drag-handle {
content: " ";
height: calc(var(--vscode-sash-size) * 2);
width: calc(var(--vscode-sash-size) * 2);
z-index: 100;
display: block;
cursor: all-scroll;
position: absolute;
}
.monaco-sash.horizontal.orthogonal-edge-north:not(.disabled)
> .orthogonal-drag-handle.start,
.monaco-sash.horizontal.orthogonal-edge-south:not(.disabled)
> .orthogonal-drag-handle.end {
cursor: nwse-resize;
}
.monaco-sash.horizontal.orthogonal-edge-north:not(.disabled)
> .orthogonal-drag-handle.end,
.monaco-sash.horizontal.orthogonal-edge-south:not(.disabled)
> .orthogonal-drag-handle.start {
cursor: nesw-resize;
}
.monaco-sash.vertical > .orthogonal-drag-handle.start {
left: calc(var(--vscode-sash-size) * -0.5);
top: calc(var(--vscode-sash-size) * -1);
}
.monaco-sash.vertical > .orthogonal-drag-handle.end {
left: calc(var(--vscode-sash-size) * -0.5);
bottom: calc(var(--vscode-sash-size) * -1);
}
.monaco-sash.horizontal > .orthogonal-drag-handle.start {
top: calc(var(--vscode-sash-size) * -0.5);
left: calc(var(--vscode-sash-size) * -1);
}
.monaco-sash.horizontal > .orthogonal-drag-handle.end {
top: calc(var(--vscode-sash-size) * -0.5);
right: calc(var(--vscode-sash-size) * -1);
}
.monaco-sash:before {
content: '';
pointer-events: none;
position: absolute;
width: 100%;
height: 100%;
background: transparent;
}
.monaco-enable-motion .monaco-sash:before {
transition: background-color 0.1s ease-out;
}
.monaco-sash.hover:before,
.monaco-sash.active:before {
background: var(--vscode-sash-hoverBorder);
}
.monaco-sash.vertical:before {
width: var(--vscode-sash-hover-size);
left: calc(50% - (var(--vscode-sash-hover-size) / 2));
}
.monaco-sash.horizontal:before {
height: var(--vscode-sash-hover-size);
top: calc(50% - (var(--vscode-sash-hover-size) / 2));
}
.pointer-events-disabled {
pointer-events: none !important;
}
/** Debug **/
.monaco-sash.debug {
background: cyan;
}
.monaco-sash.debug.disabled {
background: rgba(0, 255, 255, 0.2);
}
.monaco-sash.debug:not(.disabled) > .orthogonal-drag-handle {
background: red;
}
+451
View File
@@ -0,0 +1,451 @@
import { getWindow, append, $, addDisposableListener, EventHelper, isHTMLElement } from '../../dom.js';
import { createStyleSheet } from '../../domStylesheets.js';
import { DomEmitter } from '../../event.js';
import { EventType, Gesture } from '../../touch.js';
import { Delayer } from '../../../common/async.js';
import { memoize } from '../../../common/decorators.js';
import { Emitter } from '../../../common/event.js';
import { DisposableStore, Disposable, toDisposable } from '../../../common/lifecycle.js';
import { isMacintosh } from '../../../common/platform.js';
import './sash.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
/**
* Allow the sashes to be visible at runtime.
* @remark Use for development purposes only.
*/
const DEBUG = false;
var OrthogonalEdge;
(function (OrthogonalEdge) {
OrthogonalEdge["North"] = "north";
OrthogonalEdge["South"] = "south";
OrthogonalEdge["East"] = "east";
OrthogonalEdge["West"] = "west";
})(OrthogonalEdge || (OrthogonalEdge = {}));
let globalSize = 4;
const onDidChangeGlobalSize = new Emitter();
let globalHoverDelay = 300;
const onDidChangeHoverDelay = new Emitter();
class MouseEventFactory {
constructor(el) {
this.el = el;
this.disposables = new DisposableStore();
}
get onPointerMove() {
return this.disposables.add(new DomEmitter(getWindow(this.el), 'mousemove')).event;
}
get onPointerUp() {
return this.disposables.add(new DomEmitter(getWindow(this.el), 'mouseup')).event;
}
dispose() {
this.disposables.dispose();
}
}
__decorate([
memoize
], MouseEventFactory.prototype, "onPointerMove", null);
__decorate([
memoize
], MouseEventFactory.prototype, "onPointerUp", null);
class GestureEventFactory {
get onPointerMove() {
return this.disposables.add(new DomEmitter(this.el, EventType.Change)).event;
}
get onPointerUp() {
return this.disposables.add(new DomEmitter(this.el, EventType.End)).event;
}
constructor(el) {
this.el = el;
this.disposables = new DisposableStore();
}
dispose() {
this.disposables.dispose();
}
}
__decorate([
memoize
], GestureEventFactory.prototype, "onPointerMove", null);
__decorate([
memoize
], GestureEventFactory.prototype, "onPointerUp", null);
class OrthogonalPointerEventFactory {
get onPointerMove() {
return this.factory.onPointerMove;
}
get onPointerUp() {
return this.factory.onPointerUp;
}
constructor(factory) {
this.factory = factory;
}
dispose() {
// noop
}
}
__decorate([
memoize
], OrthogonalPointerEventFactory.prototype, "onPointerMove", null);
__decorate([
memoize
], OrthogonalPointerEventFactory.prototype, "onPointerUp", null);
const PointerEventsDisabledCssClass = 'pointer-events-disabled';
/**
* The {@link Sash} is the UI component which allows the user to resize other
* components. It's usually an invisible horizontal or vertical line which, when
* hovered, becomes highlighted and can be dragged along the perpendicular dimension
* to its direction.
*
* Features:
* - Touch event handling
* - Corner sash support
* - Hover with different mouse cursor support
* - Configurable hover size
* - Linked sash support, for 2x2 corner sashes
*/
class Sash extends Disposable {
get state() { return this._state; }
get orthogonalStartSash() { return this._orthogonalStartSash; }
get orthogonalEndSash() { return this._orthogonalEndSash; }
/**
* The state of a sash defines whether it can be interacted with by the user
* as well as what mouse cursor to use, when hovered.
*/
set state(state) {
if (this._state === state) {
return;
}
this.el.classList.toggle('disabled', state === 0 /* SashState.Disabled */);
this.el.classList.toggle('minimum', state === 1 /* SashState.AtMinimum */);
this.el.classList.toggle('maximum', state === 2 /* SashState.AtMaximum */);
this._state = state;
this.onDidEnablementChange.fire(state);
}
/**
* An event which fires whenever the user starts dragging this sash.
*/
get onDidStart() { return this._onDidStart.event; }
/**
* An event which fires whenever the user moves the mouse while
* dragging this sash.
*/
get onDidChange() { return this._onDidChange.event; }
/**
* An event which fires whenever the user double clicks this sash.
*/
get onDidReset() { return this._onDidReset.event; }
/**
* An event which fires whenever the user stops dragging this sash.
*/
get onDidEnd() { return this._onDidEnd.event; }
/**
* A reference to another sash, perpendicular to this one, which
* aligns at the start of this one. A corner sash will be created
* automatically at that location.
*
* The start of a horizontal sash is its left-most position.
* The start of a vertical sash is its top-most position.
*/
set orthogonalStartSash(sash) {
if (this._orthogonalStartSash === sash) {
return;
}
this.orthogonalStartDragHandleDisposables.clear();
this.orthogonalStartSashDisposables.clear();
if (sash) {
const onChange = (state) => {
this.orthogonalStartDragHandleDisposables.clear();
if (state !== 0 /* SashState.Disabled */) {
this._orthogonalStartDragHandle = append(this.el, $('.orthogonal-drag-handle.start'));
this.orthogonalStartDragHandleDisposables.add(toDisposable(() => this._orthogonalStartDragHandle.remove()));
this.orthogonalStartDragHandleDisposables.add(addDisposableListener(this._orthogonalStartDragHandle, 'mouseenter', () => Sash.onMouseEnter(sash)));
this.orthogonalStartDragHandleDisposables.add(addDisposableListener(this._orthogonalStartDragHandle, 'mouseleave', () => Sash.onMouseLeave(sash)));
}
};
this.orthogonalStartSashDisposables.add(sash.onDidEnablementChange.event(onChange, this));
onChange(sash.state);
}
this._orthogonalStartSash = sash;
}
/**
* A reference to another sash, perpendicular to this one, which
* aligns at the end of this one. A corner sash will be created
* automatically at that location.
*
* The end of a horizontal sash is its right-most position.
* The end of a vertical sash is its bottom-most position.
*/
set orthogonalEndSash(sash) {
if (this._orthogonalEndSash === sash) {
return;
}
this.orthogonalEndDragHandleDisposables.clear();
this.orthogonalEndSashDisposables.clear();
if (sash) {
const onChange = (state) => {
this.orthogonalEndDragHandleDisposables.clear();
if (state !== 0 /* SashState.Disabled */) {
this._orthogonalEndDragHandle = append(this.el, $('.orthogonal-drag-handle.end'));
this.orthogonalEndDragHandleDisposables.add(toDisposable(() => this._orthogonalEndDragHandle.remove()));
this.orthogonalEndDragHandleDisposables.add(addDisposableListener(this._orthogonalEndDragHandle, 'mouseenter', () => Sash.onMouseEnter(sash)));
this.orthogonalEndDragHandleDisposables.add(addDisposableListener(this._orthogonalEndDragHandle, 'mouseleave', () => Sash.onMouseLeave(sash)));
}
};
this.orthogonalEndSashDisposables.add(sash.onDidEnablementChange.event(onChange, this));
onChange(sash.state);
}
this._orthogonalEndSash = sash;
}
constructor(container, layoutProvider, options) {
super();
this.hoverDelay = globalHoverDelay;
this.hoverDelayer = this._register(new Delayer(this.hoverDelay));
this._state = 3 /* SashState.Enabled */;
this.onDidEnablementChange = this._register(new Emitter());
this._onDidStart = this._register(new Emitter());
this._onDidChange = this._register(new Emitter());
this._onDidReset = this._register(new Emitter());
this._onDidEnd = this._register(new Emitter());
this.orthogonalStartSashDisposables = this._register(new DisposableStore());
this.orthogonalStartDragHandleDisposables = this._register(new DisposableStore());
this.orthogonalEndSashDisposables = this._register(new DisposableStore());
this.orthogonalEndDragHandleDisposables = this._register(new DisposableStore());
/**
* A linked sash will be forwarded the same user interactions and events
* so it moves exactly the same way as this sash.
*
* Useful in 2x2 grids. Not meant for widespread usage.
*/
this.linkedSash = undefined;
this.el = append(container, $('.monaco-sash'));
if (options.orthogonalEdge) {
this.el.classList.add(`orthogonal-edge-${options.orthogonalEdge}`);
}
if (isMacintosh) {
this.el.classList.add('mac');
}
this._register(addDisposableListener(this.el, 'mousedown', e => this.onPointerStart(e, new MouseEventFactory(container))));
this._register(addDisposableListener(this.el, 'dblclick', e => this.onPointerDoublePress(e)));
this._register(addDisposableListener(this.el, 'mouseenter', () => Sash.onMouseEnter(this)));
this._register(addDisposableListener(this.el, 'mouseleave', () => Sash.onMouseLeave(this)));
this._register(Gesture.addTarget(this.el));
this._register(addDisposableListener(this.el, EventType.Start, e => this.onPointerStart(e, new GestureEventFactory(this.el))));
let doubleTapTimeout = undefined;
this._register(addDisposableListener(this.el, EventType.Tap, event => {
if (doubleTapTimeout) {
clearTimeout(doubleTapTimeout);
doubleTapTimeout = undefined;
this.onPointerDoublePress(event);
return;
}
clearTimeout(doubleTapTimeout);
doubleTapTimeout = setTimeout(() => doubleTapTimeout = undefined, 250);
}));
if (typeof options.size === 'number') {
this.size = options.size;
if (options.orientation === 0 /* Orientation.VERTICAL */) {
this.el.style.width = `${this.size}px`;
}
else {
this.el.style.height = `${this.size}px`;
}
}
else {
this.size = globalSize;
this._register(onDidChangeGlobalSize.event(size => {
this.size = size;
this.layout();
}));
}
this._register(onDidChangeHoverDelay.event(delay => this.hoverDelay = delay));
this.layoutProvider = layoutProvider;
this.orthogonalStartSash = options.orthogonalStartSash;
this.orthogonalEndSash = options.orthogonalEndSash;
this.orientation = options.orientation || 0 /* Orientation.VERTICAL */;
if (this.orientation === 1 /* Orientation.HORIZONTAL */) {
this.el.classList.add('horizontal');
this.el.classList.remove('vertical');
}
else {
this.el.classList.remove('horizontal');
this.el.classList.add('vertical');
}
this.el.classList.toggle('debug', DEBUG);
this.layout();
}
onPointerStart(event, pointerEventFactory) {
EventHelper.stop(event);
let isMultisashResize = false;
// eslint-disable-next-line local/code-no-any-casts
if (!event.__orthogonalSashEvent) {
const orthogonalSash = this.getOrthogonalSash(event);
if (orthogonalSash) {
isMultisashResize = true;
// eslint-disable-next-line local/code-no-any-casts
event.__orthogonalSashEvent = true;
orthogonalSash.onPointerStart(event, new OrthogonalPointerEventFactory(pointerEventFactory));
}
}
// eslint-disable-next-line local/code-no-any-casts
if (this.linkedSash && !event.__linkedSashEvent) {
// eslint-disable-next-line local/code-no-any-casts
event.__linkedSashEvent = true;
this.linkedSash.onPointerStart(event, new OrthogonalPointerEventFactory(pointerEventFactory));
}
if (!this.state) {
return;
}
// eslint-disable-next-line no-restricted-syntax
const iframes = this.el.ownerDocument.getElementsByTagName('iframe');
for (const iframe of iframes) {
iframe.classList.add(PointerEventsDisabledCssClass); // disable mouse events on iframes as long as we drag the sash
}
const startX = event.pageX;
const startY = event.pageY;
const altKey = event.altKey;
const startEvent = { startX, currentX: startX, startY, currentY: startY, altKey };
this.el.classList.add('active');
this._onDidStart.fire(startEvent);
// fix https://github.com/microsoft/vscode/issues/21675
const style = createStyleSheet(this.el);
const updateStyle = () => {
let cursor = '';
if (isMultisashResize) {
cursor = 'all-scroll';
}
else if (this.orientation === 1 /* Orientation.HORIZONTAL */) {
if (this.state === 1 /* SashState.AtMinimum */) {
cursor = 's-resize';
}
else if (this.state === 2 /* SashState.AtMaximum */) {
cursor = 'n-resize';
}
else {
cursor = isMacintosh ? 'row-resize' : 'ns-resize';
}
}
else {
if (this.state === 1 /* SashState.AtMinimum */) {
cursor = 'e-resize';
}
else if (this.state === 2 /* SashState.AtMaximum */) {
cursor = 'w-resize';
}
else {
cursor = isMacintosh ? 'col-resize' : 'ew-resize';
}
}
style.textContent = `* { cursor: ${cursor} !important; }`;
};
const disposables = new DisposableStore();
updateStyle();
if (!isMultisashResize) {
this.onDidEnablementChange.event(updateStyle, null, disposables);
}
const onPointerMove = (e) => {
EventHelper.stop(e, false);
const event = { startX, currentX: e.pageX, startY, currentY: e.pageY, altKey };
this._onDidChange.fire(event);
};
const onPointerUp = (e) => {
EventHelper.stop(e, false);
style.remove();
this.el.classList.remove('active');
this._onDidEnd.fire();
disposables.dispose();
for (const iframe of iframes) {
iframe.classList.remove(PointerEventsDisabledCssClass);
}
};
pointerEventFactory.onPointerMove(onPointerMove, null, disposables);
pointerEventFactory.onPointerUp(onPointerUp, null, disposables);
disposables.add(pointerEventFactory);
}
onPointerDoublePress(e) {
const orthogonalSash = this.getOrthogonalSash(e);
if (orthogonalSash) {
orthogonalSash._onDidReset.fire();
}
if (this.linkedSash) {
this.linkedSash._onDidReset.fire();
}
this._onDidReset.fire();
}
static onMouseEnter(sash, fromLinkedSash = false) {
if (sash.el.classList.contains('active')) {
sash.hoverDelayer.cancel();
sash.el.classList.add('hover');
}
else {
sash.hoverDelayer.trigger(() => sash.el.classList.add('hover'), sash.hoverDelay).then(undefined, () => { });
}
if (!fromLinkedSash && sash.linkedSash) {
Sash.onMouseEnter(sash.linkedSash, true);
}
}
static onMouseLeave(sash, fromLinkedSash = false) {
sash.hoverDelayer.cancel();
sash.el.classList.remove('hover');
if (!fromLinkedSash && sash.linkedSash) {
Sash.onMouseLeave(sash.linkedSash, true);
}
}
/**
* Forcefully stop any user interactions with this sash.
* Useful when hiding a parent component, while the user is still
* interacting with the sash.
*/
clearSashHoverState() {
Sash.onMouseLeave(this);
}
/**
* Layout the sash. The sash will size and position itself
* based on its provided {@link ISashLayoutProvider layout provider}.
*/
layout() {
if (this.orientation === 0 /* Orientation.VERTICAL */) {
const verticalProvider = this.layoutProvider;
this.el.style.left = verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px';
if (verticalProvider.getVerticalSashTop) {
this.el.style.top = verticalProvider.getVerticalSashTop(this) + 'px';
}
if (verticalProvider.getVerticalSashHeight) {
this.el.style.height = verticalProvider.getVerticalSashHeight(this) + 'px';
}
}
else {
const horizontalProvider = this.layoutProvider;
this.el.style.top = horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px';
if (horizontalProvider.getHorizontalSashLeft) {
this.el.style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px';
}
if (horizontalProvider.getHorizontalSashWidth) {
this.el.style.width = horizontalProvider.getHorizontalSashWidth(this) + 'px';
}
}
}
getOrthogonalSash(e) {
const target = e.initialTarget ?? e.target;
if (!target || !(isHTMLElement(target))) {
return undefined;
}
if (target.classList.contains('orthogonal-drag-handle')) {
return target.classList.contains('start') ? this.orthogonalStartSash : this.orthogonalEndSash;
}
return undefined;
}
dispose() {
super.dispose();
this.el.remove();
}
}
export { OrthogonalEdge, Sash };
@@ -0,0 +1,214 @@
import { addDisposableListener, EventType, getDomNodePagePosition } from '../../dom.js';
import { createFastDomNode } from '../../fastDomNode.js';
import { GlobalPointerMoveMonitor } from '../../globalPointerMoveMonitor.js';
import { ScrollbarArrow } from './scrollbarArrow.js';
import { ScrollbarVisibilityController } from './scrollbarVisibilityController.js';
import { Widget } from '../widget.js';
import { isWindows } from '../../../common/platform.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* The orthogonal distance to the slider at which dragging "resets". This implements "snapping"
*/
const POINTER_DRAG_RESET_DISTANCE = 140;
class AbstractScrollbar extends Widget {
constructor(opts) {
super();
this._lazyRender = opts.lazyRender;
this._host = opts.host;
this._scrollable = opts.scrollable;
this._scrollByPage = opts.scrollByPage;
this._scrollbarState = opts.scrollbarState;
this._visibilityController = this._register(new ScrollbarVisibilityController(opts.visibility, 'visible scrollbar ' + opts.extraScrollbarClassName, 'invisible scrollbar ' + opts.extraScrollbarClassName));
this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
this._pointerMoveMonitor = this._register(new GlobalPointerMoveMonitor());
this._shouldRender = true;
this.domNode = createFastDomNode(document.createElement('div'));
this.domNode.setAttribute('role', 'presentation');
this.domNode.setAttribute('aria-hidden', 'true');
this._visibilityController.setDomNode(this.domNode);
this.domNode.setPosition('absolute');
this._register(addDisposableListener(this.domNode.domNode, EventType.POINTER_DOWN, (e) => this._domNodePointerDown(e)));
}
// ----------------- creation
/**
* Creates the dom node for an arrow & adds it to the container
*/
_createArrow(opts) {
const arrow = this._register(new ScrollbarArrow(opts));
this.domNode.domNode.appendChild(arrow.bgDomNode);
this.domNode.domNode.appendChild(arrow.domNode);
}
/**
* Creates the slider dom node, adds it to the container & hooks up the events
*/
_createSlider(top, left, width, height) {
this.slider = createFastDomNode(document.createElement('div'));
this.slider.setClassName('slider');
this.slider.setPosition('absolute');
this.slider.setTop(top);
this.slider.setLeft(left);
if (typeof width === 'number') {
this.slider.setWidth(width);
}
if (typeof height === 'number') {
this.slider.setHeight(height);
}
this.slider.setLayerHinting(true);
this.slider.setContain('strict');
this.domNode.domNode.appendChild(this.slider.domNode);
this._register(addDisposableListener(this.slider.domNode, EventType.POINTER_DOWN, (e) => {
if (e.button === 0) {
e.preventDefault();
this._sliderPointerDown(e);
}
}));
this.onclick(this.slider.domNode, e => {
if (e.leftButton) {
e.stopPropagation();
}
});
}
// ----------------- Update state
_onElementSize(visibleSize) {
if (this._scrollbarState.setVisibleSize(visibleSize)) {
this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
this._shouldRender = true;
if (!this._lazyRender) {
this.render();
}
}
return this._shouldRender;
}
_onElementScrollSize(elementScrollSize) {
if (this._scrollbarState.setScrollSize(elementScrollSize)) {
this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
this._shouldRender = true;
if (!this._lazyRender) {
this.render();
}
}
return this._shouldRender;
}
_onElementScrollPosition(elementScrollPosition) {
if (this._scrollbarState.setScrollPosition(elementScrollPosition)) {
this._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());
this._shouldRender = true;
if (!this._lazyRender) {
this.render();
}
}
return this._shouldRender;
}
// ----------------- rendering
beginReveal() {
this._visibilityController.setShouldBeVisible(true);
}
beginHide() {
this._visibilityController.setShouldBeVisible(false);
}
render() {
if (!this._shouldRender) {
return;
}
this._shouldRender = false;
this._renderDomNode(this._scrollbarState.getRectangleLargeSize(), this._scrollbarState.getRectangleSmallSize());
this._updateSlider(this._scrollbarState.getSliderSize(), this._scrollbarState.getArrowSize() + this._scrollbarState.getSliderPosition());
}
// ----------------- DOM events
_domNodePointerDown(e) {
if (e.target !== this.domNode.domNode) {
return;
}
this._onPointerDown(e);
}
delegatePointerDown(e) {
const domTop = this.domNode.domNode.getClientRects()[0].top;
const sliderStart = domTop + this._scrollbarState.getSliderPosition();
const sliderStop = domTop + this._scrollbarState.getSliderPosition() + this._scrollbarState.getSliderSize();
const pointerPos = this._sliderPointerPosition(e);
if (sliderStart <= pointerPos && pointerPos <= sliderStop) {
// Act as if it was a pointer down on the slider
if (e.button === 0) {
e.preventDefault();
this._sliderPointerDown(e);
}
}
else {
// Act as if it was a pointer down on the scrollbar
this._onPointerDown(e);
}
}
_onPointerDown(e) {
let offsetX;
let offsetY;
if (e.target === this.domNode.domNode && typeof e.offsetX === 'number' && typeof e.offsetY === 'number') {
offsetX = e.offsetX;
offsetY = e.offsetY;
}
else {
const domNodePosition = getDomNodePagePosition(this.domNode.domNode);
offsetX = e.pageX - domNodePosition.left;
offsetY = e.pageY - domNodePosition.top;
}
const isMouse = (e.pointerType === 'mouse');
const isLeftClick = (e.button === 0);
if (isLeftClick || !isMouse) {
const offset = this._pointerDownRelativePosition(offsetX, offsetY);
this._setDesiredScrollPositionNow(this._scrollByPage
? this._scrollbarState.getDesiredScrollPositionFromOffsetPaged(offset)
: this._scrollbarState.getDesiredScrollPositionFromOffset(offset));
}
if (isLeftClick) {
// left button
e.preventDefault();
this._sliderPointerDown(e);
}
}
_sliderPointerDown(e) {
if (!e.target || !(e.target instanceof Element)) {
return;
}
const initialPointerPosition = this._sliderPointerPosition(e);
const initialPointerOrthogonalPosition = this._sliderOrthogonalPointerPosition(e);
const initialScrollbarState = this._scrollbarState.clone();
this.slider.toggleClassName('active', true);
this._pointerMoveMonitor.startMonitoring(e.target, e.pointerId, e.buttons, (pointerMoveData) => {
const pointerOrthogonalPosition = this._sliderOrthogonalPointerPosition(pointerMoveData);
const pointerOrthogonalDelta = Math.abs(pointerOrthogonalPosition - initialPointerOrthogonalPosition);
if (isWindows && pointerOrthogonalDelta > POINTER_DRAG_RESET_DISTANCE) {
// The pointer has wondered away from the scrollbar => reset dragging
this._setDesiredScrollPositionNow(initialScrollbarState.getScrollPosition());
return;
}
const pointerPosition = this._sliderPointerPosition(pointerMoveData);
const pointerDelta = pointerPosition - initialPointerPosition;
this._setDesiredScrollPositionNow(initialScrollbarState.getDesiredScrollPositionFromDelta(pointerDelta));
}, () => {
this.slider.toggleClassName('active', false);
this._host.onDragEnd();
});
this._host.onDragStart();
}
_setDesiredScrollPositionNow(_desiredScrollPosition) {
const desiredScrollPosition = {};
this.writeScrollPosition(desiredScrollPosition, _desiredScrollPosition);
this._scrollable.setScrollPositionNow(desiredScrollPosition);
}
updateScrollbarSize(scrollbarSize) {
this._updateScrollbarSize(scrollbarSize);
this._scrollbarState.setScrollbarSize(scrollbarSize);
this._shouldRender = true;
if (!this._lazyRender) {
this.render();
}
}
isNeeded() {
return this._scrollbarState.isNeeded();
}
}
export { AbstractScrollbar };
@@ -0,0 +1,91 @@
import { StandardWheelEvent } from '../../mouseEvent.js';
import { AbstractScrollbar } from './abstractScrollbar.js';
import { ARROW_IMG_SIZE } from './scrollbarArrow.js';
import { ScrollbarState } from './scrollbarState.js';
import { Codicon } from '../../../common/codicons.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class HorizontalScrollbar extends AbstractScrollbar {
constructor(scrollable, options, host) {
const scrollDimensions = scrollable.getScrollDimensions();
const scrollPosition = scrollable.getCurrentScrollPosition();
super({
lazyRender: options.lazyRender,
host: host,
scrollbarState: new ScrollbarState((options.horizontalHasArrows ? options.arrowSize : 0), (options.horizontal === 2 /* ScrollbarVisibility.Hidden */ ? 0 : options.horizontalScrollbarSize), (options.vertical === 2 /* ScrollbarVisibility.Hidden */ ? 0 : options.verticalScrollbarSize), scrollDimensions.width, scrollDimensions.scrollWidth, scrollPosition.scrollLeft),
visibility: options.horizontal,
extraScrollbarClassName: 'horizontal',
scrollable: scrollable,
scrollByPage: options.scrollByPage
});
if (options.horizontalHasArrows) {
const arrowDelta = (options.arrowSize - ARROW_IMG_SIZE) / 2;
const scrollbarDelta = (options.horizontalScrollbarSize - ARROW_IMG_SIZE) / 2;
this._createArrow({
className: 'scra',
icon: Codicon.scrollbarButtonLeft,
top: scrollbarDelta,
left: arrowDelta,
bottom: undefined,
right: undefined,
bgWidth: options.arrowSize,
bgHeight: options.horizontalScrollbarSize,
onActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 1, 0)),
});
this._createArrow({
className: 'scra',
icon: Codicon.scrollbarButtonRight,
top: scrollbarDelta,
left: undefined,
bottom: undefined,
right: arrowDelta,
bgWidth: options.arrowSize,
bgHeight: options.horizontalScrollbarSize,
onActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, -1, 0)),
});
}
this._createSlider(Math.floor((options.horizontalScrollbarSize - options.horizontalSliderSize) / 2), 0, undefined, options.horizontalSliderSize);
}
_updateSlider(sliderSize, sliderPosition) {
this.slider.setWidth(sliderSize);
this.slider.setLeft(sliderPosition);
}
_renderDomNode(largeSize, smallSize) {
this.domNode.setWidth(largeSize);
this.domNode.setHeight(smallSize);
this.domNode.setLeft(0);
this.domNode.setBottom(0);
}
onDidScroll(e) {
this._shouldRender = this._onElementScrollSize(e.scrollWidth) || this._shouldRender;
this._shouldRender = this._onElementScrollPosition(e.scrollLeft) || this._shouldRender;
this._shouldRender = this._onElementSize(e.width) || this._shouldRender;
return this._shouldRender;
}
_pointerDownRelativePosition(offsetX, offsetY) {
return offsetX;
}
_sliderPointerPosition(e) {
return e.pageX;
}
_sliderOrthogonalPointerPosition(e) {
return e.pageY;
}
_updateScrollbarSize(size) {
this.slider.setHeight(size);
}
writeScrollPosition(target, scrollPosition) {
target.scrollLeft = scrollPosition;
}
updateOptions(options) {
this.updateScrollbarSize(options.horizontal === 2 /* ScrollbarVisibility.Hidden */ ? 0 : options.horizontalScrollbarSize);
this._scrollbarState.setOppositeScrollbarSize(options.vertical === 2 /* ScrollbarVisibility.Hidden */ ? 0 : options.verticalScrollbarSize);
this._visibilityController.setVisibility(options.horizontal);
this._scrollByPage = options.scrollByPage;
}
}
export { HorizontalScrollbar };
@@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* Arrows */
.monaco-scrollable-element > .scrollbar > .scra {
cursor: pointer;
font-size: 11px !important;
}
.monaco-scrollable-element > .visible {
opacity: 1;
/* Background rule added for IE9 - to allow clicks on dom node */
background:rgba(0,0,0,0);
transition: opacity 100ms linear;
/* In front of peek view */
z-index: 11;
}
.monaco-scrollable-element > .invisible {
opacity: 0;
pointer-events: none;
}
.monaco-scrollable-element > .invisible.fade {
transition: opacity 800ms linear;
}
/* Scrollable Content Inset Shadow */
.monaco-scrollable-element > .shadow {
position: absolute;
display: none;
}
.monaco-scrollable-element > .shadow.top {
display: block;
top: 0;
left: 3px;
height: 3px;
width: 100%;
box-shadow: var(--vscode-scrollbar-shadow) 0 6px 6px -6px inset;
}
.monaco-scrollable-element > .shadow.left {
display: block;
top: 3px;
left: 0;
height: 100%;
width: 3px;
box-shadow: var(--vscode-scrollbar-shadow) 6px 0 6px -6px inset;
}
.monaco-scrollable-element > .shadow.top-left-corner {
display: block;
top: 0;
left: 0;
height: 3px;
width: 3px;
}
.monaco-scrollable-element > .shadow.top.left {
box-shadow: var(--vscode-scrollbar-shadow) 6px 0 6px -6px inset;
}
.monaco-scrollable-element > .scrollbar {
background: var(--vscode-scrollbar-background);
}
.monaco-scrollable-element > .scrollbar > .slider {
background: var(--vscode-scrollbarSlider-background);
}
.monaco-scrollable-element > .scrollbar > .slider:hover {
background: var(--vscode-scrollbarSlider-hoverBackground);
}
.monaco-scrollable-element > .scrollbar > .slider.active {
background: var(--vscode-scrollbarSlider-activeBackground);
}
@@ -0,0 +1,603 @@
import { isChrome, getZoomFactor } from '../../browser.js';
import { getWindow, addDisposableListener, EventType, scheduleAtNextAnimationFrame } from '../../dom.js';
import { createFastDomNode } from '../../fastDomNode.js';
import { StandardWheelEvent } from '../../mouseEvent.js';
import { HorizontalScrollbar } from './horizontalScrollbar.js';
import { VerticalScrollbar } from './verticalScrollbar.js';
import { Widget } from '../widget.js';
import { TimeoutTimer } from '../../../common/async.js';
import { Emitter } from '../../../common/event.js';
import { dispose } from '../../../common/lifecycle.js';
import { isMacintosh } from '../../../common/platform.js';
import { Scrollable } from '../../../common/scrollable.js';
import './media/scrollbars.css';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const HIDE_TIMEOUT = 500;
const SCROLL_WHEEL_SENSITIVITY = 50;
class MouseWheelClassifierItem {
constructor(timestamp, deltaX, deltaY) {
this.timestamp = timestamp;
this.deltaX = deltaX;
this.deltaY = deltaY;
this.score = 0;
}
}
class MouseWheelClassifier {
static { this.INSTANCE = new MouseWheelClassifier(); }
constructor() {
this._capacity = 5;
this._memory = [];
this._front = -1;
this._rear = -1;
}
isPhysicalMouseWheel() {
if (this._front === -1 && this._rear === -1) {
// no elements
return false;
}
// 0.5 * last + 0.25 * 2nd last + 0.125 * 3rd last + ...
let remainingInfluence = 1;
let score = 0;
let iteration = 1;
let index = this._rear;
do {
const influence = (index === this._front ? remainingInfluence : Math.pow(2, -iteration));
remainingInfluence -= influence;
score += this._memory[index].score * influence;
if (index === this._front) {
break;
}
index = (this._capacity + index - 1) % this._capacity;
iteration++;
} while (true);
return (score <= 0.5);
}
acceptStandardWheelEvent(e) {
if (isChrome) {
const targetWindow = getWindow(e.browserEvent);
const pageZoomFactor = getZoomFactor(targetWindow);
// On Chrome, the incoming delta events are multiplied with the OS zoom factor.
// The OS zoom factor can be reverse engineered by using the device pixel ratio and the configured zoom factor into account.
this.accept(Date.now(), e.deltaX * pageZoomFactor, e.deltaY * pageZoomFactor);
}
else {
this.accept(Date.now(), e.deltaX, e.deltaY);
}
}
accept(timestamp, deltaX, deltaY) {
let previousItem = null;
const item = new MouseWheelClassifierItem(timestamp, deltaX, deltaY);
if (this._front === -1 && this._rear === -1) {
this._memory[0] = item;
this._front = 0;
this._rear = 0;
}
else {
previousItem = this._memory[this._rear];
this._rear = (this._rear + 1) % this._capacity;
if (this._rear === this._front) {
// Drop oldest
this._front = (this._front + 1) % this._capacity;
}
this._memory[this._rear] = item;
}
item.score = this._computeScore(item, previousItem);
}
/**
* A score between 0 and 1 for `item`.
* - a score towards 0 indicates that the source appears to be a physical mouse wheel
* - a score towards 1 indicates that the source appears to be a touchpad or magic mouse, etc.
*/
_computeScore(item, previousItem) {
if (Math.abs(item.deltaX) > 0 && Math.abs(item.deltaY) > 0) {
// both axes exercised => definitely not a physical mouse wheel
return 1;
}
let score = 0.5;
if (!this._isAlmostInt(item.deltaX) || !this._isAlmostInt(item.deltaY)) {
// non-integer deltas => indicator that this is not a physical mouse wheel
score += 0.25;
}
// Non-accelerating scroll => indicator that this is a physical mouse wheel
// These can be identified by seeing whether they are the module of one another.
if (previousItem) {
const absDeltaX = Math.abs(item.deltaX);
const absDeltaY = Math.abs(item.deltaY);
const absPreviousDeltaX = Math.abs(previousItem.deltaX);
const absPreviousDeltaY = Math.abs(previousItem.deltaY);
// Min 1 to avoid division by zero, module 1 will still be 0.
const minDeltaX = Math.max(Math.min(absDeltaX, absPreviousDeltaX), 1);
const minDeltaY = Math.max(Math.min(absDeltaY, absPreviousDeltaY), 1);
const maxDeltaX = Math.max(absDeltaX, absPreviousDeltaX);
const maxDeltaY = Math.max(absDeltaY, absPreviousDeltaY);
const isSameModulo = (maxDeltaX % minDeltaX === 0 && maxDeltaY % minDeltaY === 0);
if (isSameModulo) {
score -= 0.5;
}
}
return Math.min(Math.max(score, 0), 1);
}
_isAlmostInt(value) {
const epsilon = Number.EPSILON * 100; // Use a small tolerance factor for floating-point errors
const delta = Math.abs(Math.round(value) - value);
return (delta < 0.01 + epsilon);
}
}
class AbstractScrollableElement extends Widget {
get onScroll() { return this._onScroll.event; }
get options() {
return this._options;
}
constructor(element, options, scrollable) {
super();
this._inertialTimeout = null;
this._inertialSpeed = { X: 0, Y: 0 };
this._onScroll = this._register(new Emitter());
this._onWillScroll = this._register(new Emitter());
element.style.overflow = 'hidden';
this._options = resolveOptions(options);
this._scrollable = scrollable;
this._register(this._scrollable.onScroll((e) => {
this._onWillScroll.fire(e);
this._onDidScroll(e);
this._onScroll.fire(e);
}));
const scrollbarHost = {
onMouseWheel: (mouseWheelEvent) => this._onMouseWheel(mouseWheelEvent),
onDragStart: () => this._onDragStart(),
onDragEnd: () => this._onDragEnd(),
};
this._verticalScrollbar = this._register(new VerticalScrollbar(this._scrollable, this._options, scrollbarHost));
this._horizontalScrollbar = this._register(new HorizontalScrollbar(this._scrollable, this._options, scrollbarHost));
this._domNode = document.createElement('div');
this._domNode.className = 'monaco-scrollable-element ' + this._options.className;
this._domNode.setAttribute('role', 'presentation');
this._domNode.style.position = 'relative';
this._domNode.style.overflow = 'hidden';
this._domNode.appendChild(element);
this._domNode.appendChild(this._horizontalScrollbar.domNode.domNode);
this._domNode.appendChild(this._verticalScrollbar.domNode.domNode);
if (this._options.useShadows) {
this._leftShadowDomNode = createFastDomNode(document.createElement('div'));
this._leftShadowDomNode.setClassName('shadow');
this._domNode.appendChild(this._leftShadowDomNode.domNode);
this._topShadowDomNode = createFastDomNode(document.createElement('div'));
this._topShadowDomNode.setClassName('shadow');
this._domNode.appendChild(this._topShadowDomNode.domNode);
this._topLeftShadowDomNode = createFastDomNode(document.createElement('div'));
this._topLeftShadowDomNode.setClassName('shadow');
this._domNode.appendChild(this._topLeftShadowDomNode.domNode);
}
else {
this._leftShadowDomNode = null;
this._topShadowDomNode = null;
this._topLeftShadowDomNode = null;
}
this._listenOnDomNode = this._options.listenOnDomNode || this._domNode;
this._mouseWheelToDispose = [];
this._setListeningToMouseWheel(this._options.handleMouseWheel);
this.onmouseover(this._listenOnDomNode, (e) => this._onMouseOver(e));
this.onmouseleave(this._listenOnDomNode, (e) => this._onMouseLeave(e));
this._hideTimeout = this._register(new TimeoutTimer());
this._isDragging = false;
this._mouseIsOver = false;
this._shouldRender = true;
this._revealOnScroll = true;
}
dispose() {
this._mouseWheelToDispose = dispose(this._mouseWheelToDispose);
if (this._inertialTimeout) {
this._inertialTimeout.dispose();
this._inertialTimeout = null;
}
super.dispose();
}
/**
* Get the generated 'scrollable' dom node
*/
getDomNode() {
return this._domNode;
}
getOverviewRulerLayoutInfo() {
return {
parent: this._domNode,
insertBefore: this._verticalScrollbar.domNode.domNode,
};
}
/**
* Delegate a pointer down event to the vertical scrollbar.
* This is to help with clicking somewhere else and having the scrollbar react.
*/
delegateVerticalScrollbarPointerDown(browserEvent) {
this._verticalScrollbar.delegatePointerDown(browserEvent);
}
getScrollDimensions() {
return this._scrollable.getScrollDimensions();
}
setScrollDimensions(dimensions) {
this._scrollable.setScrollDimensions(dimensions, false);
}
/**
* Update the class name of the scrollable element.
*/
updateClassName(newClassName) {
this._options.className = newClassName;
// Defaults are different on Macs
if (isMacintosh) {
this._options.className += ' mac';
}
this._domNode.className = 'monaco-scrollable-element ' + this._options.className;
}
/**
* Update configuration options for the scrollbar.
*/
updateOptions(newOptions) {
if (typeof newOptions.handleMouseWheel !== 'undefined') {
this._options.handleMouseWheel = newOptions.handleMouseWheel;
this._setListeningToMouseWheel(this._options.handleMouseWheel);
}
if (typeof newOptions.mouseWheelScrollSensitivity !== 'undefined') {
this._options.mouseWheelScrollSensitivity = newOptions.mouseWheelScrollSensitivity;
}
if (typeof newOptions.fastScrollSensitivity !== 'undefined') {
this._options.fastScrollSensitivity = newOptions.fastScrollSensitivity;
}
if (typeof newOptions.scrollPredominantAxis !== 'undefined') {
this._options.scrollPredominantAxis = newOptions.scrollPredominantAxis;
}
if (typeof newOptions.horizontal !== 'undefined') {
this._options.horizontal = newOptions.horizontal;
}
if (typeof newOptions.vertical !== 'undefined') {
this._options.vertical = newOptions.vertical;
}
if (typeof newOptions.horizontalScrollbarSize !== 'undefined') {
this._options.horizontalScrollbarSize = newOptions.horizontalScrollbarSize;
}
if (typeof newOptions.verticalScrollbarSize !== 'undefined') {
this._options.verticalScrollbarSize = newOptions.verticalScrollbarSize;
}
if (typeof newOptions.scrollByPage !== 'undefined') {
this._options.scrollByPage = newOptions.scrollByPage;
}
this._horizontalScrollbar.updateOptions(this._options);
this._verticalScrollbar.updateOptions(this._options);
if (!this._options.lazyRender) {
this._render();
}
}
delegateScrollFromMouseWheelEvent(browserEvent) {
this._onMouseWheel(new StandardWheelEvent(browserEvent));
}
async _periodicSync() {
let scheduleAgain = false;
if (this._inertialSpeed.X !== 0 || this._inertialSpeed.Y !== 0) {
this._scrollable.setScrollPositionNow({
scrollTop: this._scrollable.getCurrentScrollPosition().scrollTop - this._inertialSpeed.Y * 100,
scrollLeft: this._scrollable.getCurrentScrollPosition().scrollLeft - this._inertialSpeed.X * 100
});
this._inertialSpeed.X *= 0.9;
this._inertialSpeed.Y *= 0.9;
if (Math.abs(this._inertialSpeed.X) < 0.01) {
this._inertialSpeed.X = 0;
}
if (Math.abs(this._inertialSpeed.Y) < 0.01) {
this._inertialSpeed.Y = 0;
}
scheduleAgain = (this._inertialSpeed.X !== 0 || this._inertialSpeed.Y !== 0);
}
if (scheduleAgain) {
if (!this._inertialTimeout) {
this._inertialTimeout = new TimeoutTimer();
}
this._inertialTimeout.cancelAndSet(() => this._periodicSync(), 1000 / 60);
}
else {
this._inertialTimeout?.dispose();
this._inertialTimeout = null;
}
}
// -------------------- mouse wheel scrolling --------------------
_setListeningToMouseWheel(shouldListen) {
const isListening = (this._mouseWheelToDispose.length > 0);
if (isListening === shouldListen) {
// No change
return;
}
// Stop listening (if necessary)
this._mouseWheelToDispose = dispose(this._mouseWheelToDispose);
// Start listening (if necessary)
if (shouldListen) {
const onMouseWheel = (browserEvent) => {
this._onMouseWheel(new StandardWheelEvent(browserEvent));
};
this._mouseWheelToDispose.push(addDisposableListener(this._listenOnDomNode, EventType.MOUSE_WHEEL, onMouseWheel, { passive: false }));
}
}
_onMouseWheel(e) {
if (e.browserEvent?.defaultPrevented) {
return;
}
const classifier = MouseWheelClassifier.INSTANCE;
{
classifier.acceptStandardWheelEvent(e);
}
// useful for creating unit tests:
// console.log(`${Date.now()}, ${e.deltaY}, ${e.deltaX}`);
let didScroll = false;
if (e.deltaY || e.deltaX) {
let deltaY = e.deltaY * this._options.mouseWheelScrollSensitivity;
let deltaX = e.deltaX * this._options.mouseWheelScrollSensitivity;
if (this._options.scrollPredominantAxis) {
if (this._options.scrollYToX && deltaX + deltaY === 0) {
// when configured to map Y to X and we both see
// no dominant axis and X and Y are competing with
// identical values into opposite directions, we
// ignore the delta as we cannot make a decision then
deltaX = deltaY = 0;
}
else if (Math.abs(deltaY) >= Math.abs(deltaX)) {
deltaX = 0;
}
else {
deltaY = 0;
}
}
if (this._options.flipAxes) {
[deltaY, deltaX] = [deltaX, deltaY];
}
// Convert vertical scrolling to horizontal if shift is held, this
// is handled at a higher level on Mac
const shiftConvert = !isMacintosh && e.browserEvent && e.browserEvent.shiftKey;
if ((this._options.scrollYToX || shiftConvert) && !deltaX) {
deltaX = deltaY;
deltaY = 0;
}
if (e.browserEvent && e.browserEvent.altKey) {
// fastScrolling
deltaX = deltaX * this._options.fastScrollSensitivity;
deltaY = deltaY * this._options.fastScrollSensitivity;
}
const futureScrollPosition = this._scrollable.getFutureScrollPosition();
let desiredScrollPosition = {};
if (deltaY) {
const deltaScrollTop = SCROLL_WHEEL_SENSITIVITY * deltaY;
// Here we convert values such as -0.3 to -1 or 0.3 to 1, otherwise low speed scrolling will never scroll
const desiredScrollTop = futureScrollPosition.scrollTop - (deltaScrollTop < 0 ? Math.floor(deltaScrollTop) : Math.ceil(deltaScrollTop));
this._verticalScrollbar.writeScrollPosition(desiredScrollPosition, desiredScrollTop);
}
if (deltaX) {
const deltaScrollLeft = SCROLL_WHEEL_SENSITIVITY * deltaX;
// Here we convert values such as -0.3 to -1 or 0.3 to 1, otherwise low speed scrolling will never scroll
const desiredScrollLeft = futureScrollPosition.scrollLeft - (deltaScrollLeft < 0 ? Math.floor(deltaScrollLeft) : Math.ceil(deltaScrollLeft));
this._horizontalScrollbar.writeScrollPosition(desiredScrollPosition, desiredScrollLeft);
}
// Check that we are scrolling towards a location which is valid
desiredScrollPosition = this._scrollable.validateScrollPosition(desiredScrollPosition);
if (this._options.inertialScroll && (deltaX || deltaY) && !classifier.isPhysicalMouseWheel()) {
let startPeriodic = false;
// Only start periodic if it's not running
if (this._inertialSpeed.X === 0 && this._inertialSpeed.Y === 0) {
startPeriodic = true;
}
this._inertialSpeed.Y = (deltaY < 0 ? -1 : 1) * (Math.abs(deltaY) ** 1.02);
this._inertialSpeed.X = (deltaX < 0 ? -1 : 1) * (Math.abs(deltaX) ** 1.02);
if (startPeriodic) {
this._periodicSync();
}
}
if (futureScrollPosition.scrollLeft !== desiredScrollPosition.scrollLeft || futureScrollPosition.scrollTop !== desiredScrollPosition.scrollTop) {
const canPerformSmoothScroll = (this._options.mouseWheelSmoothScroll
&& classifier.isPhysicalMouseWheel());
if (canPerformSmoothScroll) {
this._scrollable.setScrollPositionSmooth(desiredScrollPosition);
}
else {
this._scrollable.setScrollPositionNow(desiredScrollPosition);
}
didScroll = true;
}
}
let consumeMouseWheel = didScroll;
if (!consumeMouseWheel && this._options.alwaysConsumeMouseWheel) {
consumeMouseWheel = true;
}
if (!consumeMouseWheel && this._options.consumeMouseWheelIfScrollbarIsNeeded && (this._verticalScrollbar.isNeeded() || this._horizontalScrollbar.isNeeded())) {
consumeMouseWheel = true;
}
if (consumeMouseWheel) {
e.preventDefault();
e.stopPropagation();
}
}
_onDidScroll(e) {
this._shouldRender = this._horizontalScrollbar.onDidScroll(e) || this._shouldRender;
this._shouldRender = this._verticalScrollbar.onDidScroll(e) || this._shouldRender;
if (this._options.useShadows) {
this._shouldRender = true;
}
if (this._revealOnScroll) {
this._reveal();
}
if (!this._options.lazyRender) {
this._render();
}
}
/**
* Render / mutate the DOM now.
* Should be used together with the ctor option `lazyRender`.
*/
renderNow() {
if (!this._options.lazyRender) {
throw new Error('Please use `lazyRender` together with `renderNow`!');
}
this._render();
}
_render() {
if (!this._shouldRender) {
return;
}
this._shouldRender = false;
this._horizontalScrollbar.render();
this._verticalScrollbar.render();
if (this._options.useShadows) {
const scrollState = this._scrollable.getCurrentScrollPosition();
const enableTop = scrollState.scrollTop > 0;
const enableLeft = scrollState.scrollLeft > 0;
const leftClassName = (enableLeft ? ' left' : '');
const topClassName = (enableTop ? ' top' : '');
const topLeftClassName = (enableLeft || enableTop ? ' top-left-corner' : '');
this._leftShadowDomNode.setClassName(`shadow${leftClassName}`);
this._topShadowDomNode.setClassName(`shadow${topClassName}`);
this._topLeftShadowDomNode.setClassName(`shadow${topLeftClassName}${topClassName}${leftClassName}`);
}
}
// -------------------- fade in / fade out --------------------
_onDragStart() {
this._isDragging = true;
this._reveal();
}
_onDragEnd() {
this._isDragging = false;
this._hide();
}
_onMouseLeave(e) {
this._mouseIsOver = false;
this._hide();
}
_onMouseOver(e) {
this._mouseIsOver = true;
this._reveal();
}
_reveal() {
this._verticalScrollbar.beginReveal();
this._horizontalScrollbar.beginReveal();
this._scheduleHide();
}
_hide() {
if (!this._mouseIsOver && !this._isDragging) {
this._verticalScrollbar.beginHide();
this._horizontalScrollbar.beginHide();
}
}
_scheduleHide() {
if (!this._mouseIsOver && !this._isDragging) {
this._hideTimeout.cancelAndSet(() => this._hide(), HIDE_TIMEOUT);
}
}
}
class ScrollableElement extends AbstractScrollableElement {
constructor(element, options) {
options = options || {};
options.mouseWheelSmoothScroll = false;
const scrollable = new Scrollable({
forceIntegerValues: true,
smoothScrollDuration: 0,
scheduleAtNextAnimationFrame: (callback) => scheduleAtNextAnimationFrame(getWindow(element), callback)
});
super(element, options, scrollable);
this._register(scrollable);
}
setScrollPosition(update) {
this._scrollable.setScrollPositionNow(update);
}
}
class SmoothScrollableElement extends AbstractScrollableElement {
constructor(element, options, scrollable) {
super(element, options, scrollable);
}
setScrollPosition(update) {
if (update.reuseAnimation) {
this._scrollable.setScrollPositionSmooth(update, update.reuseAnimation);
}
else {
this._scrollable.setScrollPositionNow(update);
}
}
getScrollPosition() {
return this._scrollable.getCurrentScrollPosition();
}
}
class DomScrollableElement extends AbstractScrollableElement {
constructor(element, options) {
options = options || {};
options.mouseWheelSmoothScroll = false;
const scrollable = new Scrollable({
forceIntegerValues: false, // See https://github.com/microsoft/vscode/issues/139877
smoothScrollDuration: 0,
scheduleAtNextAnimationFrame: (callback) => scheduleAtNextAnimationFrame(getWindow(element), callback)
});
super(element, options, scrollable);
this._register(scrollable);
this._element = element;
this._register(this.onScroll((e) => {
if (e.scrollTopChanged) {
this._element.scrollTop = e.scrollTop;
}
if (e.scrollLeftChanged) {
this._element.scrollLeft = e.scrollLeft;
}
}));
this.scanDomNode();
}
setScrollPosition(update) {
this._scrollable.setScrollPositionNow(update);
}
getScrollPosition() {
return this._scrollable.getCurrentScrollPosition();
}
scanDomNode() {
// width, scrollLeft, scrollWidth, height, scrollTop, scrollHeight
this.setScrollDimensions({
width: this._element.clientWidth,
scrollWidth: this._element.scrollWidth,
height: this._element.clientHeight,
scrollHeight: this._element.scrollHeight
});
this.setScrollPosition({
scrollLeft: this._element.scrollLeft,
scrollTop: this._element.scrollTop,
});
}
}
function resolveOptions(opts) {
const result = {
lazyRender: (typeof opts.lazyRender !== 'undefined' ? opts.lazyRender : false),
className: (typeof opts.className !== 'undefined' ? opts.className : ''),
useShadows: (typeof opts.useShadows !== 'undefined' ? opts.useShadows : true),
handleMouseWheel: (typeof opts.handleMouseWheel !== 'undefined' ? opts.handleMouseWheel : true),
flipAxes: (typeof opts.flipAxes !== 'undefined' ? opts.flipAxes : false),
consumeMouseWheelIfScrollbarIsNeeded: (typeof opts.consumeMouseWheelIfScrollbarIsNeeded !== 'undefined' ? opts.consumeMouseWheelIfScrollbarIsNeeded : false),
alwaysConsumeMouseWheel: (typeof opts.alwaysConsumeMouseWheel !== 'undefined' ? opts.alwaysConsumeMouseWheel : false),
scrollYToX: (typeof opts.scrollYToX !== 'undefined' ? opts.scrollYToX : false),
mouseWheelScrollSensitivity: (typeof opts.mouseWheelScrollSensitivity !== 'undefined' ? opts.mouseWheelScrollSensitivity : 1),
fastScrollSensitivity: (typeof opts.fastScrollSensitivity !== 'undefined' ? opts.fastScrollSensitivity : 5),
scrollPredominantAxis: (typeof opts.scrollPredominantAxis !== 'undefined' ? opts.scrollPredominantAxis : true),
mouseWheelSmoothScroll: (typeof opts.mouseWheelSmoothScroll !== 'undefined' ? opts.mouseWheelSmoothScroll : true),
inertialScroll: (typeof opts.inertialScroll !== 'undefined' ? opts.inertialScroll : false),
arrowSize: (typeof opts.arrowSize !== 'undefined' ? opts.arrowSize : 11),
listenOnDomNode: (typeof opts.listenOnDomNode !== 'undefined' ? opts.listenOnDomNode : null),
horizontal: (typeof opts.horizontal !== 'undefined' ? opts.horizontal : 1 /* ScrollbarVisibility.Auto */),
horizontalScrollbarSize: (typeof opts.horizontalScrollbarSize !== 'undefined' ? opts.horizontalScrollbarSize : 10),
horizontalSliderSize: (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : 0),
horizontalHasArrows: (typeof opts.horizontalHasArrows !== 'undefined' ? opts.horizontalHasArrows : false),
vertical: (typeof opts.vertical !== 'undefined' ? opts.vertical : 1 /* ScrollbarVisibility.Auto */),
verticalScrollbarSize: (typeof opts.verticalScrollbarSize !== 'undefined' ? opts.verticalScrollbarSize : 10),
verticalHasArrows: (typeof opts.verticalHasArrows !== 'undefined' ? opts.verticalHasArrows : false),
verticalSliderSize: (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : 0),
scrollByPage: (typeof opts.scrollByPage !== 'undefined' ? opts.scrollByPage : false)
};
result.horizontalSliderSize = (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : result.horizontalScrollbarSize);
result.verticalSliderSize = (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : result.verticalScrollbarSize);
// Defaults are different on Macs
if (isMacintosh) {
result.className += ' mac';
}
return result;
}
export { AbstractScrollableElement, DomScrollableElement, MouseWheelClassifier, ScrollableElement, SmoothScrollableElement };
@@ -0,0 +1,78 @@
import { GlobalPointerMoveMonitor } from '../../globalPointerMoveMonitor.js';
import { Widget } from '../widget.js';
import { TimeoutTimer } from '../../../common/async.js';
import { ThemeIcon } from '../../../common/themables.js';
import { addStandardDisposableListener, EventType, WindowIntervalTimer, getWindow } from '../../dom.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* The arrow image size.
*/
const ARROW_IMG_SIZE = 11;
class ScrollbarArrow extends Widget {
constructor(opts) {
super();
this._onActivate = opts.onActivate;
this.bgDomNode = document.createElement('div');
this.bgDomNode.className = 'arrow-background';
this.bgDomNode.style.position = 'absolute';
this.bgDomNode.style.width = opts.bgWidth + 'px';
this.bgDomNode.style.height = opts.bgHeight + 'px';
if (typeof opts.top !== 'undefined') {
this.bgDomNode.style.top = '0px';
}
if (typeof opts.left !== 'undefined') {
this.bgDomNode.style.left = '0px';
}
if (typeof opts.bottom !== 'undefined') {
this.bgDomNode.style.bottom = '0px';
}
if (typeof opts.right !== 'undefined') {
this.bgDomNode.style.right = '0px';
}
this.domNode = document.createElement('div');
this.domNode.className = opts.className;
this.domNode.classList.add(...ThemeIcon.asClassNameArray(opts.icon));
this.domNode.style.position = 'absolute';
this.domNode.style.width = ARROW_IMG_SIZE + 'px';
this.domNode.style.height = ARROW_IMG_SIZE + 'px';
if (typeof opts.top !== 'undefined') {
this.domNode.style.top = opts.top + 'px';
}
if (typeof opts.left !== 'undefined') {
this.domNode.style.left = opts.left + 'px';
}
if (typeof opts.bottom !== 'undefined') {
this.domNode.style.bottom = opts.bottom + 'px';
}
if (typeof opts.right !== 'undefined') {
this.domNode.style.right = opts.right + 'px';
}
this._pointerMoveMonitor = this._register(new GlobalPointerMoveMonitor());
this._register(addStandardDisposableListener(this.bgDomNode, EventType.POINTER_DOWN, (e) => this._arrowPointerDown(e)));
this._register(addStandardDisposableListener(this.domNode, EventType.POINTER_DOWN, (e) => this._arrowPointerDown(e)));
this._pointerdownRepeatTimer = this._register(new WindowIntervalTimer());
this._pointerdownScheduleRepeatTimer = this._register(new TimeoutTimer());
}
_arrowPointerDown(e) {
if (!e.target || !(e.target instanceof Element)) {
return;
}
const scheduleRepeater = () => {
this._pointerdownRepeatTimer.cancelAndSet(() => this._onActivate(), 1000 / 24, getWindow(e));
};
this._onActivate();
this._pointerdownRepeatTimer.cancel();
this._pointerdownScheduleRepeatTimer.cancelAndSet(scheduleRepeater, 200);
this._pointerMoveMonitor.startMonitoring(e.target, e.pointerId, e.buttons, (pointerMoveData) => { }, () => {
this._pointerdownRepeatTimer.cancel();
this._pointerdownScheduleRepeatTimer.cancel();
});
e.preventDefault();
}
}
export { ARROW_IMG_SIZE, ScrollbarArrow };
@@ -0,0 +1,163 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* The minimal size of the slider (such that it can still be clickable) -- it is artificially enlarged.
*/
const MINIMUM_SLIDER_SIZE = 20;
class ScrollbarState {
constructor(arrowSize, scrollbarSize, oppositeScrollbarSize, visibleSize, scrollSize, scrollPosition) {
this._scrollbarSize = Math.round(scrollbarSize);
this._oppositeScrollbarSize = Math.round(oppositeScrollbarSize);
this._arrowSize = Math.round(arrowSize);
this._visibleSize = visibleSize;
this._scrollSize = scrollSize;
this._scrollPosition = scrollPosition;
this._computedAvailableSize = 0;
this._computedIsNeeded = false;
this._computedSliderSize = 0;
this._computedSliderRatio = 0;
this._computedSliderPosition = 0;
this._refreshComputedValues();
}
clone() {
return new ScrollbarState(this._arrowSize, this._scrollbarSize, this._oppositeScrollbarSize, this._visibleSize, this._scrollSize, this._scrollPosition);
}
setVisibleSize(visibleSize) {
const iVisibleSize = Math.round(visibleSize);
if (this._visibleSize !== iVisibleSize) {
this._visibleSize = iVisibleSize;
this._refreshComputedValues();
return true;
}
return false;
}
setScrollSize(scrollSize) {
const iScrollSize = Math.round(scrollSize);
if (this._scrollSize !== iScrollSize) {
this._scrollSize = iScrollSize;
this._refreshComputedValues();
return true;
}
return false;
}
setScrollPosition(scrollPosition) {
const iScrollPosition = Math.round(scrollPosition);
if (this._scrollPosition !== iScrollPosition) {
this._scrollPosition = iScrollPosition;
this._refreshComputedValues();
return true;
}
return false;
}
setScrollbarSize(scrollbarSize) {
this._scrollbarSize = Math.round(scrollbarSize);
}
setOppositeScrollbarSize(oppositeScrollbarSize) {
this._oppositeScrollbarSize = Math.round(oppositeScrollbarSize);
}
static _computeValues(oppositeScrollbarSize, arrowSize, visibleSize, scrollSize, scrollPosition) {
const computedAvailableSize = Math.max(0, visibleSize - oppositeScrollbarSize);
const computedRepresentableSize = Math.max(0, computedAvailableSize - 2 * arrowSize);
const computedIsNeeded = (scrollSize > 0 && scrollSize > visibleSize);
if (!computedIsNeeded) {
// There is no need for a slider
return {
computedAvailableSize: Math.round(computedAvailableSize),
computedIsNeeded: computedIsNeeded,
computedSliderSize: Math.round(computedRepresentableSize),
computedSliderRatio: 0,
computedSliderPosition: 0,
};
}
// We must artificially increase the size of the slider if needed, since the slider would be too small to grab with the mouse otherwise
const computedSliderSize = Math.round(Math.max(MINIMUM_SLIDER_SIZE, Math.floor(visibleSize * computedRepresentableSize / scrollSize)));
// The slider can move from 0 to `computedRepresentableSize` - `computedSliderSize`
// in the same way `scrollPosition` can move from 0 to `scrollSize` - `visibleSize`.
const computedSliderRatio = (computedRepresentableSize - computedSliderSize) / (scrollSize - visibleSize);
const computedSliderPosition = (scrollPosition * computedSliderRatio);
return {
computedAvailableSize: Math.round(computedAvailableSize),
computedIsNeeded: computedIsNeeded,
computedSliderSize: Math.round(computedSliderSize),
computedSliderRatio: computedSliderRatio,
computedSliderPosition: Math.round(computedSliderPosition),
};
}
_refreshComputedValues() {
const r = ScrollbarState._computeValues(this._oppositeScrollbarSize, this._arrowSize, this._visibleSize, this._scrollSize, this._scrollPosition);
this._computedAvailableSize = r.computedAvailableSize;
this._computedIsNeeded = r.computedIsNeeded;
this._computedSliderSize = r.computedSliderSize;
this._computedSliderRatio = r.computedSliderRatio;
this._computedSliderPosition = r.computedSliderPosition;
}
getArrowSize() {
return this._arrowSize;
}
getScrollPosition() {
return this._scrollPosition;
}
getRectangleLargeSize() {
return this._computedAvailableSize;
}
getRectangleSmallSize() {
return this._scrollbarSize;
}
isNeeded() {
return this._computedIsNeeded;
}
getSliderSize() {
return this._computedSliderSize;
}
getSliderPosition() {
return this._computedSliderPosition;
}
/**
* Compute a desired `scrollPosition` such that `offset` ends up in the center of the slider.
* `offset` is based on the same coordinate system as the `sliderPosition`.
*/
getDesiredScrollPositionFromOffset(offset) {
if (!this._computedIsNeeded) {
// no need for a slider
return 0;
}
const desiredSliderPosition = offset - this._arrowSize - this._computedSliderSize / 2;
return Math.round(desiredSliderPosition / this._computedSliderRatio);
}
/**
* Compute a desired `scrollPosition` from if offset is before or after the slider position.
* If offset is before slider, treat as a page up (or left). If after, page down (or right).
* `offset` and `_computedSliderPosition` are based on the same coordinate system.
* `_visibleSize` corresponds to a "page" of lines in the returned coordinate system.
*/
getDesiredScrollPositionFromOffsetPaged(offset) {
if (!this._computedIsNeeded) {
// no need for a slider
return 0;
}
const correctedOffset = offset - this._arrowSize; // compensate if has arrows
let desiredScrollPosition = this._scrollPosition;
if (correctedOffset < this._computedSliderPosition) {
desiredScrollPosition -= this._visibleSize; // page up/left
}
else {
desiredScrollPosition += this._visibleSize; // page down/right
}
return desiredScrollPosition;
}
/**
* Compute a desired `scrollPosition` such that the slider moves by `delta`.
*/
getDesiredScrollPositionFromDelta(delta) {
if (!this._computedIsNeeded) {
// no need for a slider
return 0;
}
const desiredSliderPosition = this._computedSliderPosition + delta;
return Math.round(desiredSliderPosition / this._computedSliderRatio);
}
}
export { ScrollbarState };
@@ -0,0 +1,93 @@
import { TimeoutTimer } from '../../../common/async.js';
import { Disposable } from '../../../common/lifecycle.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class ScrollbarVisibilityController extends Disposable {
constructor(visibility, visibleClassName, invisibleClassName) {
super();
this._visibility = visibility;
this._visibleClassName = visibleClassName;
this._invisibleClassName = invisibleClassName;
this._domNode = null;
this._isVisible = false;
this._isNeeded = false;
this._rawShouldBeVisible = false;
this._shouldBeVisible = false;
this._revealTimer = this._register(new TimeoutTimer());
}
setVisibility(visibility) {
if (this._visibility !== visibility) {
this._visibility = visibility;
this._updateShouldBeVisible();
}
}
// ----------------- Hide / Reveal
setShouldBeVisible(rawShouldBeVisible) {
this._rawShouldBeVisible = rawShouldBeVisible;
this._updateShouldBeVisible();
}
_applyVisibilitySetting() {
if (this._visibility === 2 /* ScrollbarVisibility.Hidden */) {
return false;
}
if (this._visibility === 3 /* ScrollbarVisibility.Visible */) {
return true;
}
return this._rawShouldBeVisible;
}
_updateShouldBeVisible() {
const shouldBeVisible = this._applyVisibilitySetting();
if (this._shouldBeVisible !== shouldBeVisible) {
this._shouldBeVisible = shouldBeVisible;
this.ensureVisibility();
}
}
setIsNeeded(isNeeded) {
if (this._isNeeded !== isNeeded) {
this._isNeeded = isNeeded;
this.ensureVisibility();
}
}
setDomNode(domNode) {
this._domNode = domNode;
this._domNode.setClassName(this._invisibleClassName);
// Now that the flags & the dom node are in a consistent state, ensure the Hidden/Visible configuration
this.setShouldBeVisible(false);
}
ensureVisibility() {
if (!this._isNeeded) {
// Nothing to be rendered
this._hide(false);
return;
}
if (this._shouldBeVisible) {
this._reveal();
}
else {
this._hide(true);
}
}
_reveal() {
if (this._isVisible) {
return;
}
this._isVisible = true;
// The CSS animation doesn't play otherwise
this._revealTimer.setIfNotSet(() => {
this._domNode?.setClassName(this._visibleClassName);
}, 0);
}
_hide(withFadeAway) {
this._revealTimer.cancel();
if (!this._isVisible) {
return;
}
this._isVisible = false;
this._domNode?.setClassName(this._invisibleClassName + (withFadeAway ? ' fade' : ''));
}
}
export { ScrollbarVisibilityController };
@@ -0,0 +1,94 @@
import { StandardWheelEvent } from '../../mouseEvent.js';
import { AbstractScrollbar } from './abstractScrollbar.js';
import { ARROW_IMG_SIZE } from './scrollbarArrow.js';
import { ScrollbarState } from './scrollbarState.js';
import { Codicon } from '../../../common/codicons.js';
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
class VerticalScrollbar extends AbstractScrollbar {
constructor(scrollable, options, host) {
const scrollDimensions = scrollable.getScrollDimensions();
const scrollPosition = scrollable.getCurrentScrollPosition();
super({
lazyRender: options.lazyRender,
host: host,
scrollbarState: new ScrollbarState((options.verticalHasArrows ? options.arrowSize : 0), (options.vertical === 2 /* ScrollbarVisibility.Hidden */ ? 0 : options.verticalScrollbarSize),
// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom
0, scrollDimensions.height, scrollDimensions.scrollHeight, scrollPosition.scrollTop),
visibility: options.vertical,
extraScrollbarClassName: 'vertical',
scrollable: scrollable,
scrollByPage: options.scrollByPage
});
if (options.verticalHasArrows) {
const arrowDelta = (options.arrowSize - ARROW_IMG_SIZE) / 2;
const scrollbarDelta = (options.verticalScrollbarSize - ARROW_IMG_SIZE) / 2;
this._createArrow({
className: 'scra',
icon: Codicon.scrollbarButtonUp,
top: arrowDelta,
left: scrollbarDelta,
bottom: undefined,
right: undefined,
bgWidth: options.verticalScrollbarSize,
bgHeight: options.arrowSize,
onActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 0, 1)),
});
this._createArrow({
className: 'scra',
icon: Codicon.scrollbarButtonDown,
top: undefined,
left: scrollbarDelta,
bottom: arrowDelta,
right: undefined,
bgWidth: options.verticalScrollbarSize,
bgHeight: options.arrowSize,
onActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 0, -1)),
});
}
this._createSlider(0, Math.floor((options.verticalScrollbarSize - options.verticalSliderSize) / 2), options.verticalSliderSize, undefined);
}
_updateSlider(sliderSize, sliderPosition) {
this.slider.setHeight(sliderSize);
this.slider.setTop(sliderPosition);
}
_renderDomNode(largeSize, smallSize) {
this.domNode.setWidth(smallSize);
this.domNode.setHeight(largeSize);
this.domNode.setRight(0);
this.domNode.setTop(0);
}
onDidScroll(e) {
this._shouldRender = this._onElementScrollSize(e.scrollHeight) || this._shouldRender;
this._shouldRender = this._onElementScrollPosition(e.scrollTop) || this._shouldRender;
this._shouldRender = this._onElementSize(e.height) || this._shouldRender;
return this._shouldRender;
}
_pointerDownRelativePosition(offsetX, offsetY) {
return offsetY;
}
_sliderPointerPosition(e) {
return e.pageY;
}
_sliderOrthogonalPointerPosition(e) {
return e.pageX;
}
_updateScrollbarSize(size) {
this.slider.setWidth(size);
}
writeScrollPosition(target, scrollPosition) {
target.scrollTop = scrollPosition;
}
updateOptions(options) {
this.updateScrollbarSize(options.vertical === 2 /* ScrollbarVisibility.Hidden */ ? 0 : options.verticalScrollbarSize);
// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom
this._scrollbarState.setOppositeScrollbarSize(0);
this._visibilityController.setVisibility(options.vertical);
this._scrollByPage = options.scrollByPage;
}
}
export { VerticalScrollbar };
Loaded 100 of 4134 files, more files were not shown because too many files have changed in this diff. Show more