diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 09e2f6aea42..35069f5af54 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -24,29 +24,29 @@ This project incorporates components from the projects listed below. The origina 17. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) 18. language-docker (https://github.com/docker/docker) 19. language-go version 0.39.0 (https://github.com/atom/language-go) -20. language-php version 0.29.0 (https://github.com/atom/language-php) -21. language-rust version 0.4.4 (https://github.com/zargony/atom-language-rust) -22. MagicStack/MagicPython (https://github.com/MagicStack/MagicPython) -23. Microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/Microsoft/TypeScript-TmLanguage) -24. mmcgrana/textmate-clojure (https://github.com/mmcgrana/textmate-clojure) -25. octicons-code version 3.1.0 (https://octicons.github.com) -26. octicons-font version 3.1.0 (https://octicons.github.com) -27. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) -28. string_scorer version 0.1.20 (https://github.com/joshaven/string_score) -29. sublimehq/Packages (https://github.com/sublimehq/Packages) -30. SublimeText/PowerShell (https://github.com/SublimeText/PowerShell) -31. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) -32. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) -33. textmate/coffee-script.tmbundle (https://github.com/textmate/coffee-script.tmbundle) -34. textmate/css.tmbundle (https://github.com/textmate/css.tmbundle) -35. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) -36. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) -37. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) -38. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) -39. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) -40. textmate/java.tmbundle (https://github.com/textmate/java.tmbundle) -41. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) -42. textmate/less.tmbundle (https://github.com/textmate/less.tmbundle) +20. language-less (https://github.com/atom/language-less) +21. language-php version 0.29.0 (https://github.com/atom/language-php) +22. language-rust version 0.4.4 (https://github.com/zargony/atom-language-rust) +23. MagicStack/MagicPython (https://github.com/MagicStack/MagicPython) +24. Microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/Microsoft/TypeScript-TmLanguage) +25. mmcgrana/textmate-clojure (https://github.com/mmcgrana/textmate-clojure) +26. octicons-code version 3.1.0 (https://octicons.github.com) +27. octicons-font version 3.1.0 (https://octicons.github.com) +28. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) +29. string_scorer version 0.1.20 (https://github.com/joshaven/string_score) +30. sublimehq/Packages (https://github.com/sublimehq/Packages) +31. SublimeText/PowerShell (https://github.com/SublimeText/PowerShell) +32. textmate/asp.vb.net.tmbundle (https://github.com/textmate/asp.vb.net.tmbundle) +33. textmate/c.tmbundle (https://github.com/textmate/c.tmbundle) +34. textmate/coffee-script.tmbundle (https://github.com/textmate/coffee-script.tmbundle) +35. textmate/css.tmbundle (https://github.com/textmate/css.tmbundle) +36. textmate/diff.tmbundle (https://github.com/textmate/diff.tmbundle) +37. textmate/git.tmbundle (https://github.com/textmate/git.tmbundle) +38. textmate/groovy.tmbundle (https://github.com/textmate/groovy.tmbundle) +39. textmate/html.tmbundle (https://github.com/textmate/html.tmbundle) +40. textmate/ini.tmbundle (https://github.com/textmate/ini.tmbundle) +41. textmate/java.tmbundle (https://github.com/textmate/java.tmbundle) +42. textmate/javascript.tmbundle (https://github.com/textmate/javascript.tmbundle) 43. textmate/lua.tmbundle (https://github.com/textmate/lua.tmbundle) 44. textmate/make.tmbundle (https://github.com/textmate/make.tmbundle) 45. textmate/markdown.tmbundle (https://github.com/textmate/markdown.tmbundle) @@ -810,6 +810,58 @@ THE SOFTWARE. ========================================= END OF language-go NOTICES AND INFORMATION +%% language-less NOTICES AND INFORMATION BEGIN HERE +========================================= +The MIT License (MIT) + +Copyright (c) 2014 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +This package was derived from a TextMate bundle located at +https://github.com/textmate/less.tmbundle and distributed under the following +license, located in `LICENSE.md`: + +Copyright (c) 2010 Scott Kyle and Rasmus Andersson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +========================================= +END OF language-less NOTICES AND INFORMATION + %% language-php NOTICES AND INFORMATION BEGIN HERE ========================================= The MIT License (MIT) @@ -1522,29 +1574,6 @@ to the base-name name of the original file, and an extension of txt, html, or si ========================================= END OF textmate/javascript.tmbundle NOTICES AND INFORMATION -%% textmate/less.tmbundle NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2010 Scott Kyle and Rasmus Andersson - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO -EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -USE OR OTHER DEALINGS IN THE SOFTWARE. -========================================= -END OF textmate/less.tmbundle NOTICES AND INFORMATION - %% textmate/lua.tmbundle NOTICES AND INFORMATION BEGIN HERE ========================================= Copyright (c) textmate-lua.tmbundle project authors diff --git a/extensions/cpp/test/colorize-results/test_c.json b/extensions/cpp/test/colorize-results/test_c.json index d02782cd9e4..18c6925c548 100644 --- a/extensions/cpp/test/colorize-results/test_c.json +++ b/extensions/cpp/test/colorize-results/test_c.json @@ -256,11 +256,11 @@ "c": " ", "t": "c.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -344,11 +344,11 @@ "c": " ", "t": "block.c.function.leading.meta.punctuation.support.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -421,11 +421,11 @@ "c": " ", "t": "block.c.function.leading.meta.punctuation.support.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1059,11 +1059,11 @@ "c": " ", "t": "block.c.function.leading.meta.punctuation.support.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1433,11 +1433,11 @@ "c": " ", "t": "block.c.function.leading.meta.punctuation.support.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1741,11 +1741,11 @@ "c": " ", "t": "block.c.function.leading.meta.punctuation.support.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1851,11 +1851,11 @@ "c": " ", "t": "block.c.function.leading.meta.punctuation.support.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { diff --git a/extensions/cpp/test/colorize-results/test_cc.json b/extensions/cpp/test/colorize-results/test_cc.json index a5ac2a113b2..80e2b67793b 100644 --- a/extensions/cpp/test/colorize-results/test_cc.json +++ b/extensions/cpp/test/colorize-results/test_cc.json @@ -36,11 +36,11 @@ "c": " ", "t": "c.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -278,11 +278,11 @@ "c": " ", "t": "c.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -388,11 +388,11 @@ "c": " ", "t": "c.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -531,11 +531,11 @@ "c": " ", "t": "c.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -608,11 +608,11 @@ "c": " ", "t": "block.c.function.function-call.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -685,11 +685,11 @@ "c": " ", "t": "block.c.function.function-call.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -916,11 +916,11 @@ "c": " ", "t": "block.c.comment.cpp.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { @@ -1004,11 +1004,11 @@ "c": " ", "t": "block.c.function.function-call.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1059,11 +1059,11 @@ "c": " ", "t": "block.c.comment.cpp.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { @@ -1092,11 +1092,11 @@ "c": " ", "t": "block.c.function.leading.meta.punctuation.support.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1191,11 +1191,11 @@ "c": " ", "t": "c.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1257,11 +1257,11 @@ "c": " ", "t": "block.c.function.leading.meta.punctuation.support.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.support.function rgb(220, 220, 170)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.support.function rgb(121, 94, 38)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1334,11 +1334,11 @@ "c": " ", "t": "block.c.comment.cpp.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { @@ -1367,11 +1367,11 @@ "c": " ", "t": "block.c.function.function-call.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1444,11 +1444,11 @@ "c": " ", "t": "block.c.function.function-call.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -1521,11 +1521,11 @@ "c": " ", "t": "block.c.comment.cpp.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { diff --git a/extensions/cpp/test/colorize-results/test_cpp.json b/extensions/cpp/test/colorize-results/test_cpp.json index dd79aabdf54..bd19ea3c56c 100644 --- a/extensions/cpp/test/colorize-results/test_cpp.json +++ b/extensions/cpp/test/colorize-results/test_cpp.json @@ -289,11 +289,11 @@ "c": " ", "t": "c.class-struct-block.cpp.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -410,11 +410,11 @@ "c": " ", "t": "c.class-struct-block.cpp.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -564,11 +564,11 @@ "c": " ", "t": "c.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { @@ -773,11 +773,11 @@ "c": " ", "t": "c.function.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark .token.whitespace rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs .token.whitespace rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black .token.whitespace rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark .token rgb(212, 212, 212)", + "light_plus": ".vs .token rgb(0, 0, 0)", + "dark_vs": ".vs-dark .token rgb(212, 212, 212)", + "light_vs": ".vs .token rgb(0, 0, 0)", + "hc_black": ".hc-black .token rgb(255, 255, 255)" } }, { diff --git a/extensions/java/test/colorize-results/basic_java.json b/extensions/java/test/colorize-results/basic_java.json index a6a7fb865c4..e87e15340f9 100644 --- a/extensions/java/test/colorize-results/basic_java.json +++ b/extensions/java/test/colorize-results/basic_java.json @@ -1664,11 +1664,11 @@ "c": "\t", "t": "body.class.comment.java.leading.meta.punctuation.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { diff --git a/extensions/javascript/src/features/bowerJSONContribution.ts b/extensions/javascript/src/features/bowerJSONContribution.ts index 42a26dbb695..01847f77ef6 100644 --- a/extensions/javascript/src/features/bowerJSONContribution.ts +++ b/extensions/javascript/src/features/bowerJSONContribution.ts @@ -170,13 +170,11 @@ export class BowerJSONContribution implements IJSONContribution { if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']))) { let pack = location.path[location.path.length - 1]; if (typeof pack === 'string') { - let htmlContent: MarkedString[] = []; - htmlContent.push(localize('json.bower.package.hover', '{0}', pack)); return this.getInfo(pack).then(documentation => { if (documentation) { - htmlContent.push(textToMarkedString(documentation)); + return [textToMarkedString(documentation)]; } - return htmlContent; + return null; }); } } diff --git a/extensions/javascript/src/features/packageJSONContribution.ts b/extensions/javascript/src/features/packageJSONContribution.ts index 6c8a54f261d..0e78b048a79 100644 --- a/extensions/javascript/src/features/packageJSONContribution.ts +++ b/extensions/javascript/src/features/packageJSONContribution.ts @@ -211,13 +211,11 @@ export class PackageJSONContribution implements IJSONContribution { if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) { let pack = location.path[location.path.length - 1]; if (typeof pack === 'string') { - let htmlContent: MarkedString[] = []; - htmlContent.push(localize('json.npm.package.hover', '{0}', pack)); return this.getInfo(pack).then(infos => { - infos.forEach(info => { - htmlContent.push(textToMarkedString(info)); - }); - return htmlContent; + if (infos.length) { + return [infos.map(textToMarkedString).join('\n\n')]; + } + return null; }); } } diff --git a/extensions/javascript/test/colorize-results/test_jsx.json b/extensions/javascript/test/colorize-results/test_jsx.json index 2a1f91a6d6e..654e7e7a405 100644 --- a/extensions/javascript/test/colorize-results/test_jsx.json +++ b/extensions/javascript/test/colorize-results/test_jsx.json @@ -509,11 +509,11 @@ "c": " ", "t": "block.comment.expr.function.js.leading.member.meta.object.objectliteral.punctuation.var.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { @@ -608,11 +608,11 @@ "c": " ", "t": "block.comment.expr.function.js.leading.member.meta.object.objectliteral.punctuation.var.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { @@ -641,11 +641,11 @@ "c": " ", "t": "block.comment.expr.function.js.leading.member.meta.object.objectliteral.punctuation.var.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { @@ -1026,11 +1026,11 @@ "c": " ", "t": "block.comment.expr.function.js.leading.member.meta.object.objectliteral.punctuation.var.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { @@ -1202,11 +1202,11 @@ "c": " ", "t": "block.comment.expr.function.js.leading.member.meta.object.objectliteral.punctuation.var.whitespace", "r": { - "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgba(51, 51, 51, 0.2)", - "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgba(227, 228, 226, 0.156863)", - "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgba(51, 51, 51, 0.2)", - "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgba(227, 228, 226, 0.156863)" + "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.comment rgb(96, 139, 78)", + "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.comment rgb(0, 128, 0)", + "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.comment rgb(96, 139, 78)", + "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.comment rgb(0, 128, 0)", + "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.comment rgb(124, 166, 104)" } }, { diff --git a/extensions/json/server/npm-shrinkwrap.json b/extensions/json/server/npm-shrinkwrap.json index c43488d2d01..84caeb7f0ed 100644 --- a/extensions/json/server/npm-shrinkwrap.json +++ b/extensions/json/server/npm-shrinkwrap.json @@ -43,9 +43,16 @@ "resolved": "https://registry.npmjs.org/request-light/-/request-light-0.1.0.tgz" }, "vscode-json-languageservice": { - "version": "1.1.8-next.2", + "version": "2.0.0-next.2", "from": "vscode-json-languageservice@next", - "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-1.1.8-next.2.tgz" + "resolved": "https://registry.npmjs.org/vscode-json-languageservice/-/vscode-json-languageservice-2.0.0-next.2.tgz", + "dependencies": { + "vscode-languageserver-types": { + "version": "1.0.4", + "from": "vscode-languageserver-types@>=1.0.4 <2.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-1.0.4.tgz" + } + } }, "vscode-jsonrpc": { "version": "2.3.2-next.5", diff --git a/extensions/json/server/package.json b/extensions/json/server/package.json index e09bca6bf1d..acbadb593f1 100644 --- a/extensions/json/server/package.json +++ b/extensions/json/server/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "request-light": "^0.1.0", - "vscode-json-languageservice": "^1.1.8-next.2", + "vscode-json-languageservice": "^2.0.0-next.2", "vscode-languageserver": "^2.4.0-next.12", "vscode-nls": "^1.0.4" }, diff --git a/extensions/less/OSSREADME.json b/extensions/less/OSSREADME.json index 27b9d8fe26c..d0dfbef7cbb 100644 --- a/extensions/less/OSSREADME.json +++ b/extensions/less/OSSREADME.json @@ -1,25 +1,7 @@ // ATTENTION - THIS DIRECTORY CONTAINS THIRD PARTY OPEN SOURCE MATERIALS: [{ - "name": "textmate/less.tmbundle", + "name": "language-less", "version": "0.0.0", "license": "MIT", - "repositoryURL": "https://github.com/textmate/less.tmbundle", - "licenseDetail": [ - "Copyright (c) 2010 Scott Kyle and Rasmus Andersson", - "", - "Permission is hereby granted, free of charge, to any person obtaining a copy of this software ", - "and associated documentation files (the \"Software\"), to deal in the Software without restriction,", - "including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, ", - "and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, ", - "subject to the following conditions:", - "", - "The above copyright notice and this permission notice shall be included in all copies or substantial ", - "portions of the Software.", - "", - "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT ", - "LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO ", - "EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER ", - "IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE ", - "USE OR OTHER DEALINGS IN THE SOFTWARE." - ] + "repositoryURL": "https://github.com/atom/language-less" }] diff --git a/extensions/less/package.json b/extensions/less/package.json index e6b9fd6368e..865edef01d1 100644 --- a/extensions/less/package.json +++ b/extensions/less/package.json @@ -3,6 +3,9 @@ "version": "0.1.0", "publisher": "vscode", "engines": { "vscode": "*" }, + "scripts": { + "update-grammar": "node ../../build/npm/update-grammar.js atom/language-less grammars/less.cson ./syntaxes/less.tmLanguage.json" + }, "contributes": { "languages": [{ "id": "less", @@ -14,7 +17,7 @@ "grammars": [{ "language": "less", "scopeName": "source.css.less", - "path": "./syntaxes/LESS.tmLanguage" + "path": "./syntaxes/less.tmLanguage.json" }] } } \ No newline at end of file diff --git a/extensions/less/syntaxes/LESS.tmLanguage b/extensions/less/syntaxes/LESS.tmLanguage deleted file mode 100644 index 7393637647c..00000000000 --- a/extensions/less/syntaxes/LESS.tmLanguage +++ /dev/null @@ -1,434 +0,0 @@ - - - - - comment - LeSS - fileTypes - - less - - foldingStartMarker - /\*\*(?!\*)|\{\s*($|/\*(?!.*?\*/.*\S)) - foldingStopMarker - (?<!\*)\*\*/|^\s*\} - keyEquivalent - ^~L - name - LESS - patterns - - - match - \b(a|abbr|acronym|address|applet|article|area|audio|video|b|base|big|blockquote|body|br|button|caption|canvas|center|cite|code|col|colgroup|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figure|figcaption|form|frame|frameset|(h[1-6])|head|hr|html|i|iframe|img|input|ins|kbd|label|legend|li|link|map|mark|meta|menu|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|q|ruby|s|samp|script|select|small|span|strike|strong|style|sub|sup|summary|svg|table|tbody|td|textarea|tfoot|th|thead|title|tr|tt|u|ul|var|header|section|footer|aside|hgroup|time)\b - name - keyword.control.html.elements - - - begin - " - beginCaptures - - 0 - - name - punctuation.definition.string.begin.css - - - end - " - endCaptures - - 0 - - name - punctuation.definition.string.end.css - - - name - string.quoted.double.css - patterns - - - match - \\. - name - constant.character.escaped.css - - - - - begin - ' - beginCaptures - - 0 - - name - punctuation.definition.string.begin.css - - - end - ' - endCaptures - - 0 - - name - punctuation.definition.string.end.css - - - name - string.quoted.single.css - patterns - - - match - \\. - name - constant.character.escaped.css - - - - - captures - - 1 - - name - entity.other.attribute-name.class.css - - - match - (\.[a-zA-Z0-9_-]+) - - - begin - url\( - contentName - variable.parameter.url - end - \) - name - support.function.any-method.builtin.css - - - match - (#)([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b - name - constant.other.rgb-value.css - - - captures - - 0 - - name - entity.other.attribute-name.id - - - match - #[a-zA-Z0-9_:\(\)-]+ - name - meta.selector.css - - - begin - /\* - beginCaptures - - 0 - - name - punctuation.definition.comment.begin.css - - - end - \*/ - endCaptures - - 0 - - name - punctuation.definition.comment.end.css - - - name - comment.block.css - - - match - (-|\+)?\s*[0-9]+(\.[0-9]+)? - name - constant.numeric.css - - - match - (?<=[\d])(px|pt|cm|mm|in|em|rem|ex|pc)\b|% - name - keyword.other.unit.css - - - captures - - 1 - - name - entity.other.attribute-name.pseudo-element.css - - - match - (:+(after|before|not|last-child|nth-of-type|nth-child|first-child|first-letter|first-line|selection|root)) - - - captures - - 1 - - name - entity.other.attribute-name.pseudo-class.css - - - match - (:+(active|hover|link|visited|focus)) - - - captures - - 1 - - name - punctuation.definition.entity.css - - 2 - - name - entity.other.attribute-name.attribute.css - - 3 - - name - punctuation.separator.operator.css - - 4 - - name - string.unquoted.attribute-value.css - - 5 - - name - string.quoted.double.attribute-value.css - - 6 - - name - punctuation.definition.string.begin.css - - 7 - - name - punctuation.definition.string.end.css - - - match - (?i)(\[)\s*(-?[_a-z\\[[:^ascii:]]][_a-z0-9\-\\[[:^ascii:]]]*)(?:\s*([~|^$*]?=)\s*(?:(-?[_a-z\\[[:^ascii:]]][_a-z0-9\-\\[[:^ascii:]]]*)|((?>(['"])(?:[^\\]|\\.)*?(\6)))))?\s*(\]) - name - meta.attribute-selector.css - - - captures - - 1 - - name - keyword.control.at-rule.import.css - - 2 - - name - punctuation.definition.keyword.css - - - match - ^\s*((@)import\b) - name - meta.at-rule.import.css - - - captures - - 1 - - name - support.type.property-name.css.vendor - - - match - (-(?:webkit|moz|khtml|o|icab|ms)-(?:background-size|border-radius|box-shadow|opacity|border-image))\s*: - - - captures - - 1 - - name - support.type.property-name.css - - - match - \b(azimuth|background-attachment|background-color|background-clip|background-image|background-position|background-repeat|background-size|background|behavior|border-bottom-color|border-bottom-style|border-bottom-width|border-bottom|border-collapse|border-color|border-left-color|border-left-style|border-left-width|border-left|border-right-color|border-right-style|border-right-width|border-right|border-spacing|border-style|border-top-color|border-top-style|border-top-width|border-top|border-width|border-radius|border|box-shadow|bottom|caption-side|clear|clip|color|content|counter-increment|counter-reset|cue-after|cue-before|cue|cursor|direction|display|elevation|empty-cells|filter|float|font-family|font-size-adjust|font-size|font-stretch|font-style|font-variant|font-weight|font|height|left|letter-spacing|line-height|list-style-image|list-style-position|list-style-type|list-style|margin-bottom|margin-left|margin-right|margin-top|marker-offset|margin|marks|max-height|max-width|min-height|min-width|opacity|orphans|outline-color|outline-style|outline-width|outline|overflow(-[xy])?|padding-bottom|padding-left|padding-right|padding-top|padding|page-break-after|page-break-before|page-break-inside|page|pause-after|pause-before|pause|pitch-range|pitch|play-during|position|pre-wrap|quotes|richness|right|size|speak-header|speak-numeral|speak-punctuation|speech-rate|speak|stress|table-layout|text-align|text-decoration|text-indent|text-shadow|text-transform|top|unicode-bidi|vertical-align|visibility|voice-family|volume|white-space|widows|width|word-spacing|word-wrap|z-index|zoom) - - - match - \b(absolute|all-scroll|always|auto|baseline|below|bidi-override|block|bold|bolder|both|bottom|break-all|break-word|capitalize|center|char|circle|col-resize|collapse|crosshair|dashed|decimal|default|disabled|disc|distribute-all-lines|distribute-letter|distribute-space|distribute|dotted|double|e-resize|ellipsis|fixed|groove|hand|help|hidden|horizontal|ideograph-alpha|ideograph-numeric|ideograph-parenthesis|ideograph-space|inactive|inherit|inline-block|inline|inset|inside|inter-ideograph|inter-word|italic|justify|keep-all|left|lighter|line-edge|line-through|line|linear|list-item|loose|lower-alpha|lower-roman|lowercase|lr-tb|ltr|medium|middle|move|n-resize|ne-resize|newspaper|no-drop|no-repeat|nw-resize|none|normal|not-allowed|nowrap|oblique|outset|outside|overline|pointer|progress|relative|repeat-x|repeat-y|repeat|right|ridge|row-resize|rtl|s-resize|scroll|se-resize|separate|small-caps|solid|square|static|strict|super|sw-resize|table-footer-group|table-header-group|tb-rl|text-bottom|text-top|text|thick|thin|top|transparent|underline|upper-alpha|upper-roman|uppercase|vertical-ideographic|vertical-text|visible|w-resize|wait|whitespace|padding-box)\b - name - support.constant.property-value.css - - - match - (\b(?i:arial|century|comic|courier|garamond|georgia|helvetica|impact|lucida|symbol|system|tahoma|times|trebuchet|utopia|verdana|webdings|sans-serif|serif|monospace)\b) - name - support.constant.font-name.css - - - comment - http://www.w3.org/TR/CSS21/syndata.html#value-def-color - match - \b(aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow)\b - name - support.constant.color.w3c-standard-color-name.css - - - match - \b(saturate|desaturate|lighten|darken|grayscale)\b - name - support.function.any-method.builtin.less - - - match - \b(rgb|rgba|hsl|hsla|url)\b - name - support.function.any-method.builtin.css - - - captures - - 1 - - name - support.function.any-method.vendor.css - - - match - (-(?:webkit|moz|khtml|o|icab)-(?:gradient|linear-gradient)) - - - match - \b(color-stop|from|to)\b - name - support.function.any-method.webkit.gradient.css - - - captures - - 1 - - name - support.function.less - - - match - (\.[a-zA-Z0-9_-]+)\s*(;|\() - - - begin - (^[ \t]+)?(?=//) - beginCaptures - - 1 - - name - punctuation.whitespace.comment.leading.less - - - end - (?!\G) - patterns - - - begin - // - beginCaptures - - 0 - - name - punctuation.definition.comment.less - - - end - \n - name - comment.line.double-slash.less - - - - - match - (@[a-zA-Z0-9_-][\w-]*)|(\-\-[^:\),]+) - name - variable.other.less - - - match - \$|%|&|\*|\-\-|\-|\+\+|\+|~|===|==|=|!=|!==|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\|\||\?\:|\*=|(?<!\()/=|%=|\+=|\-=|&=|\^=|\/\b - name - keyword.operator.less - - - captures - - 1 - - name - punctuation.section.property-list.begin.css - - 2 - - name - punctuation.section.property-list.end.css - - - comment - Match empty braces to give proper ↩ action - match - (\{)(\}) - name - meta.brace.curly.less - - - match - \{|\} - name - meta.brace.curly.less - - - match - \(|\) - name - meta.brace.round.less - - - match - \[|\] - name - meta.brace.square.less - - - scopeName - source.css.less - uuid - 9343D324-75A1-4733-A5C0-5D1D4B6182D0 - - diff --git a/extensions/less/syntaxes/less.tmLanguage.json b/extensions/less/syntaxes/less.tmLanguage.json new file mode 100644 index 00000000000..7d59a25964d --- /dev/null +++ b/extensions/less/syntaxes/less.tmLanguage.json @@ -0,0 +1,619 @@ +{ + "name": "Less", + "scopeName": "source.css.less", + "fileTypes": [ + "less", + "less.erb", + "rc", + "gtkrc", + "gtkrc-2.0", + "themerc" + ], + "patterns": [ + { + "include": "#strings" + }, + { + "captures": { + "1": { + "name": "entity.other.attribute-name.class.mixin.css" + } + }, + "match": "(\\.[_a-zA-Z][a-zA-Z0-9_-]*(?=\\())" + }, + { + "captures": { + "1": { + "name": "entity.other.attribute-name.class.css" + }, + "2": { + "name": "punctuation.definition.entity.css" + }, + "4": { + "name": "variable.other.interpolation.less" + } + }, + "match": "((\\.)([_a-zA-Z]|(@{[a-zA-Z0-9_-]+}))[a-zA-Z0-9_-]*)" + }, + { + "captures": { + "0": { + "name": "entity.other.attribute-name.parent-selector.css" + }, + "1": { + "name": "punctuation.definition.entity.css" + } + }, + "match": "(&)[a-zA-Z0-9_-]*" + }, + { + "begin": "(format|local|url|attr|counter|counters)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "support.function.misc.css" + }, + "2": { + "name": "punctuation.section.function.css" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.function.css" + } + }, + "patterns": [ + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.css" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.css" + } + }, + "name": "string.quoted.single.css", + "patterns": [ + { + "match": "\\\\.", + "name": "constant.character.escape.css" + } + ] + }, + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.css" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.css" + } + }, + "name": "string.quoted.double.css", + "patterns": [ + { + "match": "\\\\(\\d{1,6}|.)", + "name": "constant.character.escape.css" + } + ] + }, + { + "match": "[^'\") \\t]+", + "name": "variable.parameter.misc.css" + } + ] + }, + { + "match": "(#)([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\\b(?!.*?(?(['\"])(?:[^\\\\]|\\\\.)*?(\\6)))))?\\s*(\\])", + "name": "meta.attribute-selector.css" + }, + { + "begin": "((@)import\\b)", + "beginCaptures": { + "1": { + "name": "keyword.control.at-rule.import.less" + }, + "2": { + "name": "punctuation.definition.keyword.less" + } + }, + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.import.css", + "patterns": [ + { + "match": "(?<=\\(|,|\\s)\\b(reference|optional|once|multiple|less|inline)\\b(?=\\)|,)", + "name": "keyword.control.import.option.less" + }, + { + "include": "#brace_round" + }, + { + "include": "#commas" + }, + { + "include": "#strings" + } + ] + }, + { + "captures": { + "1": { + "name": "keyword.control.at-rule.fontface.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "match": "^\\s*((@)font-face\\b)", + "name": "meta.at-rule.fontface.css" + }, + { + "captures": { + "1": { + "name": "keyword.control.at-rule.media.css" + }, + "2": { + "name": "punctuation.definition.keyword.css" + } + }, + "match": "^\\s*((@)media\\b)", + "name": "meta.at-rule.media.css" + }, + { + "match": "\\b(width|scan|resolution|orientation|monochrome|min-width|min-resolution|min-monochrome|min-height|min-device-width|min-device-height|min-device-aspect-ratio|min-color-index|min-color|min-aspect-ratio|max-width|max-resolution|max-monochrome|max-height|max-device-width|max-device-height|max-device-aspect-ratio|max-color-index|max-color|max-aspect-ratio|height|grid|device-width|device-height|device-aspect-ratio|color-index|color|aspect-ratio)\\b", + "name": "support.type.property-name.media-feature.media.css" + }, + { + "match": "\\b(tv|tty|screen|projection|print|handheld|embossed|braille|aural|all)\\b", + "name": "support.constant.media-type.media.css" + }, + { + "match": "\\b(portrait|landscape)\\b", + "name": "support.constant.property-value.media-property.media.css" + }, + { + "captures": { + "1": { + "name": "support.function.less" + } + }, + "match": "(\\.[a-zA-Z0-9_-]+)\\s*(;|\\()" + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.less" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.less" + } + }, + "end": "\\n", + "name": "comment.line.double-slash.less" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.variable.less" + } + }, + "match": "(?:@|\\-\\-)[a-zA-Z0-9_-][\\w-]*(?=\\s*)", + "name": "variable.other.less" + }, + { + "include": "#variable_interpolation" + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.property-list.begin.css" + } + }, + "end": "}", + "endCaptures": { + "0": { + "name": "punctuation.section.property-list.end.css" + } + }, + "name": "meta.property-list.css", + "patterns": [ + { + "include": "#pseudo_elements" + }, + { + "include": "#pseudo_classes" + }, + { + "include": "#variable_interpolation" + }, + { + "include": "#property_names" + }, + { + "include": "#property_names_svg" + }, + { + "include": "#property_values" + }, + { + "include": "$self" + } + ] + }, + { + "match": "\\!\\s*important", + "name": "keyword.other.important.css" + }, + { + "match": "\\*|\\/|\\-|\\+|~|=|<=|>=|<|>", + "name": "keyword.operator.less" + }, + { + "match": "\\b(not|and|when)\\b", + "name": "keyword.control.logical.operator.less" + }, + { + "match": "(?x)\n(?= 2.0.6", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "定义非空方括号的左括号之后和右括号之前的空格处理。", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "定义非空圆括号的左括号之后和右括号之前的空格处理。", - "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "定义模板字符串的左括号之后和右括号之前的空格处理。要求 TypeScript >= 2.0.6", - "format.insertSpaceAfterSemicolonInForStatements": "在 For 语句中,定义分号之后的空格处理", + "configuration.typescript": "TypeScript。", + "format.insertSpaceAfterCommaDelimiter": "定义逗号分隔符后面的空格处理。", + "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "定义匿名函数的函数关键字后面的空格处理。", + "format.insertSpaceAfterKeywordsInControlFlowStatements": "定义控制流语句中的关键字后面的空格处理。", + "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "定义 JSX 表达式左括号后面和右括号前面的空格处理。要求 TypeScript >= 2.0.6。", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "定义非空方括号的左括号后面和右括号前面的空格处理。", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "定义非空圆括号的左括号后面和右括号前面的空格处理。", + "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "定义模板字符串的左括号后面和右括号前面的空格处理。要求 TypeScript >= 2.0.6。", + "format.insertSpaceAfterSemicolonInForStatements": "在 For 语句中,定义分号后面的空格处理。", "format.insertSpaceBeforeAndAfterBinaryOperators": "定义二进制运算符后面的空格处理", - "format.placeOpenBraceOnNewLineForControlBlocks": "定义左大括号是否针对控制块而放置在新的一行", - "format.placeOpenBraceOnNewLineForFunctions": "定义左大括号是否针对函数而放置在新的一行", + "format.placeOpenBraceOnNewLineForControlBlocks": "定义控制块的左括号是否放置在新的一行。", + "format.placeOpenBraceOnNewLineForFunctions": "定义函数的左大括号是否放置在新的一行。", + "javascript.format.enable": "启用/禁用 JavaScript 格式化程序。", "javascript.reloadProjects.title": "重新加载 JavaScript 项目", - "javascript.validate.enable": "启用/禁用 JavaScript 验证", + "javascript.validate.enable": "启用/禁用 JavaScript 验证。", "typescript.check.tscVersion": "检查全局安装的 TypeScript 编译器(例如 tsc )是否不同于使用的 TypeScript 语言服务。", - "typescript.check.workspaceVersion": "检查工作区中的 TypeScript 版本是否可用", - "typescript.experimentalAutomaticTypeAcquisition": "启用自动类型获取。要求 TypeScript >= 2.0.6,并需在对其进行更改后重启。", + "typescript.check.workspaceVersion": "检查工作区中的 TypeScript 版本是否可用。", + "typescript.disableAutomaticTypeAcquisition": "禁用自动获取类型。需要 TypeScript >= 2.0.6,并且更改后需要重启。", + "typescript.format.enable": "启用/禁用默认 TypeScript 格式化程序。", "typescript.reloadProjects.title": "重新加载 TypeScript 项目", "typescript.tsdk.desc": "指定包含要使用的 tsserver 和 lib*.d.ts 文件的文件夹路径。", "typescript.tsdk_version.desc": "指定 tsserver 的版本。仅在未使用 npm 安装 tsserver 时需要。", "typescript.tsserver.experimentalAutoBuild": "启用实验性自动生成。要求安装 1.9 dev 或 2.x tsserver 版本并在更改后重启 VS Code。", - "typescript.tsserver.trace": "启用对发送到 TS 服务器的消息进行跟踪", + "typescript.tsserver.trace": "启用跟踪发送到 TS 服务器的消息。", "typescript.useCodeSnippetsOnMethodSuggest.dec": "完成函数的参数签名。", - "typescript.validate.enable": "启用/禁用 TypeScript 验证" + "typescript.validate.enable": "启用/禁用 TypeScript 验证。" } \ No newline at end of file diff --git a/i18n/chs/src/vs/code/electron-main/menus.i18n.json b/i18n/chs/src/vs/code/electron-main/menus.i18n.json index 866572b97d2..4dd27ff83af 100644 --- a/i18n/chs/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/chs/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "退出(&&X)", "miFind": "查找(&&F)", "miFindInFiles": "在文件中查找(&&I)", - "miFocusFirstGroup": "左侧组(&&L)", - "miFocusSecondGroup": "中心组(&&C)", - "miFocusThirdGroup": "右侧组(&&R)", + "miFocusFirstGroup": "第一组(&&F)", + "miFocusSecondGroup": "第二组(&&S)", + "miFocusThirdGroup": "第三组(&&T)", "miForward": "前进(&&F)", "miGotoDefinition": "转到定义(&&D)...", "miGotoFile": "转到文件(&&F)...", "miGotoLine": "转到行(&&L)...", "miGotoSymbolInFile": "转到文件中的符号(&&S)...", "miGotoSymbolInWorkspace": "转到工作区中的符号(&&W)...", + "miHideStatusbar": "隐藏状态栏(&&H)", "miInstallingUpdate": "正在安装更新...", + "miIntroductoryVideos": "介绍性视频(&&V)", + "miKeyboardShortcuts": "键盘快捷方式引用(&&K)", "miLicense": "查看许可证(&&V)", "miMarker": "问题(&&P)", - "miMoveSidebar": "移动侧边栏(&&M)", + "miMoveSidebarLeft": "向左移动侧边栏(&&M)", + "miMoveSidebarRight": "向右移动侧边栏(&&M)", "miNewFile": "新建文件(&&N)", "miNewWindow": "新建窗口(&&N)", "miNextEditor": "下一个编辑器(&&N)", @@ -84,11 +88,13 @@ "miSelectAll": "全选(&&S)", "miSelectColorTheme": "颜色主题(&&C)", "miSelectIconTheme": "文件图标主题(&&I)", + "miShowStatusbar": "显示状态栏(&&S)", "miSplitEditor": "拆分编辑器(&&E)", "miSwitchEditor": "切换编辑器(&&E)", "miSwitchGroup": "切换组(&&G)", "miToggleDebugConsole": "调试控制台(&&B)", "miToggleDevTools": "切换开发人员工具(&&T)", + "miToggleEditorLayout": "切换编辑器组布局(&&L)", "miToggleFullScreen": "切换全屏(&&F)", "miToggleIntegratedTerminal": "集成终端(&&I)", "miToggleMenuBar": "切换菜单栏(&&B)", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "切换控制字符(&&C)", "miToggleRenderWhitespace": "切换呈现空格(&&R)", "miToggleSidebar": "切换侧边栏(&&T)", - "miToggleStatusbar": "切换状态栏(&&T)", "miToggleWordWrap": "切换自动换行(&&W)", "miTwitter": "在 Twitter 上加入我们(&&J)", "miUndo": "撤消(&&U)", diff --git a/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json index 4bbe233a52f..0bec53ac3a8 100644 --- a/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/chs/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "控制光标样式,接受的值为 \"block\"、\"line\" 和 \"underline\"", "detectIndentation": "当打开文件时,将基于文件内容检测 \"editor.tabSize\" 和 \"editor.insertSpaces\"。", "editorConfigurationTitle": "编辑器", + "emptySelectionClipboard": "控制没有选择内容的复制是否复制当前行。", "folding": "控制编辑器是否启用代码折叠功能", "fontFamily": "控制字体系列。", "fontLigatures": "启用字体连字", @@ -23,7 +24,7 @@ "insertSpaces": "按 \"Tab\" 时插入空格。该设置在 `editor.detectIndentation` 启用时根据文件内容进行重写。", "insertSpaces.errorMessage": "应为 \"boolean\"。注意,值 \"auto\" 已由 \"editor.detectIndentation\" 设置替换。", "lineHeight": "控制行高。使用 0 通过字号计算行高。", - "lineNumbers": "控制行号的可见性", + "lineNumbers": "控制行号的显示。可能的值为“开”、“关”和“相对”。“相对”将显示从当前光标位置开始计数的行数。", "mouseWheelScrollSensitivity": "要对鼠标滚轮滚动事件的 \"deltaX\" 和 \"deltaY\" 使用的乘数 ", "mouseWheelZoom": "通过使用鼠标滚轮同时按住 Ctrl 可缩放编辑器的字体", "overviewRulerLanes": "控制可在概述标尺同一位置显示的效果数量", diff --git a/i18n/chs/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/chs/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index 46d5b868f43..b3f2e279f8c 100644 --- a/i18n/chs/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "显示辅助功能帮助", - "introMsg": "感谢试用 VS 代码的实验辅助功能选项。", + "introMsg": "感谢试用 VS Code 的辅助功能选项。", "outroMsg": "可以通过按 Esc 消除此工具提示并返回到编辑器。", "status": "状态:", - "tabFocusModeOffMsg": "在此编辑器中按 Tab 将插入制表符。通过按 {0} 切换此行为。", - "tabFocusModeOffMsgNoKb": "在此编辑器中按 Tab 会将焦点移动到下一个可聚焦的元素。当前无法通过键绑定触发命令 {0}。", - "tabFocusModeOnMsg": "在此编辑器中按 Tab 会将焦点移动到下一个可聚焦的元素。通过按 {0} 切换此行为。", - "tabFocusModeOnMsgNoKb": "在此编辑器中按 Tab 会将焦点移动到下一个可聚焦的元素。当前无法通过键绑定触发命令 {0}。" + "tabFocusModeOffMsg": "在当前编辑器中按 Tab 将插入制表符。通过按 {0} 切换此行为。", + "tabFocusModeOffMsgNoKb": "在当前编辑器中按 Tab 会将焦点移动到下一个可聚焦的元素。当前无法通过键绑定触发命令 {0}。", + "tabFocusModeOnMsg": "在当前编辑器中按 Tab 会将焦点移动到下一个可聚焦的元素。通过按 {0} 切换此行为。", + "tabFocusModeOnMsgNoKb": "在当前编辑器中按 Tab 会将焦点移动到下一个可聚焦的元素。当前无法通过键绑定触发命令 {0}。" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/chs/src/vs/editor/contrib/format/common/formatActions.i18n.json index 3ec5cd9442e..1833deae8ec 100644 --- a/i18n/chs/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/chs/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "格式代码" + "formatDocument.label": "设置文档格式", + "formatSelection.label": "设置选定内容的格式" } \ No newline at end of file diff --git a/i18n/chs/src/vs/editor/node/textMate/TMSyntax.i18n.json b/i18n/chs/src/vs/editor/node/textMate/TMSyntax.i18n.json index 2f1291b3d3f..7c610136bb1 100644 --- a/i18n/chs/src/vs/editor/node/textMate/TMSyntax.i18n.json +++ b/i18n/chs/src/vs/editor/node/textMate/TMSyntax.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.embeddedLanguages": "\"contributes.{0}.embeddedLanguages\" 中的无效值。必须为从作用域名称映射到语言的对象。给定值: {1}", "invalid.injectTo": "\"contributes.{0}.injectTo\" 中的值无效。必须为语言范围名称数组。提供的值: {1}", "invalid.language": "“contributes.{0}.language”中存在未知的语言。提供的值: {1}", "invalid.path.0": "“contributes.{0}.path”中应为字符串。提供的值: {1}", "invalid.path.1": "“contributes.{0}.path”({1})应包含在扩展的文件夹({2})内。这可能会使扩展不可移植。", "invalid.scopeName": "“contributes.{0}.scopeName”中应为字符串。提供的值: {1}", "vscode.extension.contributes.grammars": "用于 textmate tokenizer。", + "vscode.extension.contributes.grammars.embeddedLanguages": "如果此语法包含嵌入式语言,则为作用域名称到语言 ID 的映射。", "vscode.extension.contributes.grammars.injectTo": "此语法注入到的语言范围名称列表。", "vscode.extension.contributes.grammars.language": "此语法参与的语言标识符。", "vscode.extension.contributes.grammars.path": "tmLanguage 文件的路径。该路径是相对于扩展文件夹,通常以 \"./syntaxes/\" 开头。", diff --git a/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index c9bc1a31d88..b551cd08c42 100644 --- a/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/chs/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "取消", "doNotInstall": "否", "install": "是", "installDependeciesConfirmation": "安装”{0}“还会安装其依赖项。是否要继续?", @@ -11,6 +12,14 @@ "invalidName": "扩展无效: 清单名不匹配。", "invalidPublisher": "扩展无效: 清单发布服务器不匹配。", "invalidVersion": "扩展无效: 清单版本不匹配。", + "multipleDependentsError": "无法卸载扩展程序“{0}”。扩展程序“{1}”、“{2}”以及其他扩展程序都依赖于此。", "notExists": "找不到扩展", - "restartCode": "请先重启 Code 再重新安装 {0}。" + "ok": "确定", + "restartCode": "请先重启 Code 再重新安装 {0}。", + "singleDependentError": "无法卸载扩展程序“{0}”。扩展程序“{1}”依赖于此。", + "twoDependentsError": "无法卸载扩展程序“{0}”。扩展程序“{1}”、“{2}”依赖于此。", + "uninstallAll": "全部", + "uninstallConfirmation": "是否确定要卸载“{0}”?", + "uninstallDependeciesConfirmation": "要仅卸载“{0}”或者其依赖项也一起卸载?", + "uninstallOnly": "仅卸载“{0}”" } \ No newline at end of file diff --git a/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 71a27b6c743..b9447670346 100644 --- a/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/chs/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "属性“{0}”可以省略或其类型必须是 \"string[]\"", - "extensionDescription.activationEvents2": "必须同时指定或同时省略属性”{0}“和”{1}“", - "extensionDescription.empty": "已获得空扩展说明", - "extensionDescription.engines": "属性“{0}”为必需且其类型必须为 \"object\"", - "extensionDescription.engines.vscode": "属性“{0}”是必需的,其类型必须是“字符串”", - "extensionDescription.extensionDependencies": "属性“{0}”可以省略或其类型必须是 \"string[]\"", - "extensionDescription.main1": "属性“{0}”可以省略,或者其类型必须是“字符串”", - "extensionDescription.main2": "应在扩展文件夹({1})中包含 \"main\" ({0})。这可能会使扩展不可移植。", - "extensionDescription.main3": "必须同时指定或同时省略属性”{0}“和”{1}“", - "extensionDescription.name": "属性“{0}”是必需的,其类型必须是“字符串”", - "extensionDescription.publisher": "属性“{0}”是必需的,其类型必须是“字符串”", - "extensionDescription.version": "属性“{0}”是必需的,其类型必须是“字符串”", "vscode.extension.activationEvents": "VS Code 扩展的激活事件。", "vscode.extension.badges": "在 Marketplace 的扩展页边栏中显示的徽章数组。", "vscode.extension.badges.description": "徽章说明。", @@ -24,6 +12,7 @@ "vscode.extension.categories": "VS Code 库用于对扩展进行分类的类别。", "vscode.extension.contributes": "由此包表示的 VS Code 扩展的所有贡献。", "vscode.extension.displayName": "VS Code 库中使用的扩展的显示名称。", + "vscode.extension.engines.vscode": "对于 VS Code 扩展程序,指定该扩展程序与之兼容的 VS Code 版本。不能为 *. 例如: ^0.10.5 表示最低兼容 VS Code 版本 0.10.5。", "vscode.extension.extensionDependencies": "其他扩展的依赖关系。扩展的标识符始终是 ${publisher}.${name}。例如: vscode.csharp。", "vscode.extension.galleryBanner": "VS Code 商城使用的横幅。", "vscode.extension.galleryBanner.color": "VS Code 商城页标题上的横幅颜色。", diff --git a/i18n/chs/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/chs/src/vs/workbench/browser/actions/openSettings.i18n.json index ee44efd391e..68f5fc0195c 100644 --- a/i18n/chs/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "默认键盘快捷方式", "defaultKeybindingsHeader": "通过将键绑定放入键绑定文件中来覆盖键绑定。", "defaultName": "默认设置", + "defaultSettingsEditor": "默认设置编辑器", "defaultSettingsHeader": "通过将设置放入设置文件中来覆盖设置。", "defaultSettingsHeader2": "请参阅 http://go.microsoft.com/fwlink/?LinkId=808995 以了解最常用的设置。", "emptyKeybindingsHeader": "将键绑定放入此文件中以覆盖默认值", diff --git a/i18n/chs/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/chs/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..063a8cb7edf 100644 --- a/i18n/chs/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "水平编辑器组布局", + "toggleEditorGroupLayout": "切换编辑器组布局(垂直/水平)", + "verticalLayout": "垂直编辑器组布局", + "view": "查看" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index d1cb0fff608..b35d5aec26e 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "显示所有已打开的编辑器", "binaryDiffEditor": "二进制差异编辑器", - "centerEditorGroupPicker": "显示中心组中的编辑器", - "leftEditorGroupPicker": "显示左侧组中的编辑器", - "rightEditorGroupPicker": "显示右侧组中的编辑器", + "groupOnePicker": "在第一组中显示编辑器", + "groupThreePicker": "在第三组中显示编辑器", + "groupTwoPicker": "在第二组中显示编辑器", "textDiffEditor": "文本差异编辑器", "textEditor": "文本编辑器", "view": "查看" diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 9a230feba3b..ed8df50629c 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "关闭其他编辑器", "evenEditorGroups": "编辑器组平均宽度", "focusActiveEditorGroup": "聚焦活动编辑器组", - "focusFirstEditorGroup": "聚焦于左侧编辑器组", + "focusFirstEditorGroup": "聚焦于第一个编辑器组", "focusLastEditorInStack": "打开组中上一个编辑器", "focusNextGroup": "聚焦于下一个组", "focusPreviousGroup": "聚焦于上一个组", - "focusSecondEditorGroup": "聚焦于中心编辑器组", - "focusThirdEditorGroup": "聚焦于右侧编辑器组", + "focusSecondEditorGroup": "聚焦于第二个编辑器组", + "focusThirdEditorGroup": "聚焦于第三个编辑器组", "keepEditor": "保留编辑器", "maximizeEditor": "最大化编辑器组并隐藏边栏", "minimizeOtherEditorGroups": "最小化其他编辑器组", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "向右移动编辑器组", "moveEditorLeft": "向左移动编辑器", "moveEditorRight": "向右移动编辑器", - "moveEditorToLeftGroup": "将编辑器移动到左侧的组中", - "moveEditorToRightGroup": "将编辑器移动到右侧的组中", + "moveEditorToNextGroup": "将编辑器移动到下一组", + "moveEditorToPreviousGroup": "将编辑器移动到上一组", "navigateEditorGroups": "在编辑器组间进行导航", "navigateEditorHistoryByInput": "从历史记录里打开上一个编辑器", "navigateNext": "前进", @@ -38,12 +38,11 @@ "openPreviousEditor": "打开上一个编辑器", "openPreviousEditorInGroup": "打开组中上一个最近使用的编辑器", "openToSide": "打开到侧边", - "removeFromEditorHistory": "从编辑器历史记录中删除", "reopenClosedEditor": "重新打开已关闭的编辑器", "showAllEditors": "显示所有编辑器", - "showEditorsInCenterGroup": "显示中心组中的编辑器", + "showEditorsInFirstGroup": "在第一组中显示编辑器", "showEditorsInGroup": "显示组中的编辑器", - "showEditorsInLeftGroup": "显示左侧组中的编辑器", - "showEditorsInRightGroup": "显示右侧组中的编辑器", + "showEditorsInSecondGroup": "在第二组中显示编辑器", + "showEditorsInThirdGroup": "在第三组中显示编辑器", "splitEditor": "拆分编辑器" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index 6c89fb4e3a7..efc34530f44 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "居中", "editorOpenError": "无法打开“{0}”: {1}。", - "leftGroup": "左侧", - "rightGroup": "右侧" + "groupOneHorizontal": "顶部", + "groupOneVertical": "左侧", + "groupThreeHorizontal": "底部", + "groupThreeVertical": "右侧", + "groupTwoHorizontal": "居中", + "groupTwoVertical": "居中" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index fbab35e733b..24d4daf3f86 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0}, 编辑器组选取器", "groupLabel": "组: {0}", - "noOpenedEditors": "已打开的编辑器列表当前为空", + "noOpenedEditors": "已打开的编辑器组列表当前为空", + "noOpenedEditorsAllGroups": "已打开的编辑器列表当前为空", "noResultsFound": "未找到匹配的已打开编辑器", "noResultsFoundInGroup": "未在组中找到匹配的已打开编辑器" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/chs/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index e3938dd554b..bd0697137a4 100644 --- a/i18n/chs/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/chs/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "选择行尾序列", "selectEncoding": "选择编码", "selectLanguageMode": "选择语言模式", + "showLanguageExtensions": "搜索“{0}”的应用市场扩展程序...", "singleSelection": "行 {0},列 {1}", "singleSelectionRange": "行 {0},列 {1} (已选择{2})", "spacesSize": "空格: {0}", diff --git a/i18n/chs/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index 529f855237a..9da7700c559 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "如果此条件为 true,程序仅会在此处停止。按 Enter 接受或按 Esc 取消。", - "breakpointWidgetExpressionPlaceholder": "在表达式计算结果为 true 时中断", + "breakpointWidgetExpressionPlaceholder": "在表达式计算结果为 true 时中断。按 \"Enter\" 表示接受,\"Esc\" 表示取消。", "breakpointWidgetHitCountAriaLabel": "如果达到命中次数,程序仅会在此处停止。按 Enter 接受或按 Esc 取消。", - "breakpointWidgetHitCountPlaceholder": "在满足命中次数条件时中断", + "breakpointWidgetHitCountPlaceholder": "在满足命中次数条件时中断。按 \"Enter\" 表示接受,\"Esc\" 表示取消。", "expression": "表达式", "hitCount": "命中次数" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index cbdb10a1bed..06071273b35 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "调试: 添加条件断点...", "continueDebug": "继续", "deactivateBreakpoints": "停用断点", - "debugActionLabelAndKeybinding": "{0} ({1})", "debugAddToWatch": "调试: 添加到监视", "debugConsoleAction": "调试控制台", "debugEvaluate": "调试: 评估", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "禁用所有断点", "disconnectDebug": "断开连接", "editConditionalBreakpoint": "编辑断点...", + "editWatchExpression": "编辑表达式", "enableAllBreakpoints": "启用所有断点", "launchJsonNeedsConfigurtion": "配置或修复 \"launch.json\"", "openLaunchJson": "打开 {0}", @@ -32,7 +32,6 @@ "removeBreakpoint": "删除断点", "removeWatchExpression": "删除表达式", "renameFunctionBreakpoint": "重命名函数断点", - "renameWatchExpression": "重命名表达式", "restartDebug": "重启", "restartFrame": "重新启动框架", "runToCursor": "调试: 运行到光标", diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index b43b7f94756..1d4609c58a1 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,13 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "允许为所有文件设置断点(不考虑扩展)。", + "allowBreakpointsEverywhere": "允许在任何文件中设置断点", "debug": "调试", "debugCategory": "调试", "debugConfigurationTitle": "调试", "debugErrorEditor": "调试错误", "debugPanel": "调试控制台", - "launchConfigDoesNotExist": "启动配置“{0}”不存在。", "openExplorerOnEnd": "在调试会话结束时自动打开资源管理器 viewlet。", "toggleDebugPanel": "调试控制台", "toggleDebugViewlet": "显示调试", diff --git a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json index 50a572147dc..c0d6b84dc05 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json @@ -12,6 +12,7 @@ "functionBreakpointsNotSupported": "此调试类型不支持函数断点", "loadMoreStackFrames": "加载多个堆栈帧", "paused": "已暂停", + "process": "进程", "running": "正在运行", "stackFrameAriaLabel": "堆栈帧 {0} 行 {1} {2},调用堆栈,调试", "thread": "线程", diff --git a/i18n/chs/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/chs/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index c0d0cc181ec..61094a3e37b 100644 --- a/i18n/chs/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "debugConfigurationNames": "要在此“复合”配置期间启动的配置。仅考虑此配置类型为“复合”时。", "debugLinuxConfiguration": "特定于 Linux 的启动配置属性。", "debugName": "配置名称;在启动配置下拉菜单中显示。", "debugOSXConfiguration": "特定于 OS X 的启动配置属性。", diff --git a/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 51a9fd41e13..20ccecadb15 100644 --- a/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "建议仅在工作区文件夹上可用。", "OpenExtensionsFile.failed": "无法在 \".vscode\" 文件夹({0})内创建 \"extensions.json\" 文件。", - "OpenGlobalExtensionsStorageFile.failed": "无法在“{0}”文件夹内创建 \"extensions.json\" 文件({1})。", + "Uninstalling": "正在卸载", "builtin": "内置", "clearExtensionsInput": "清除扩展输入", "configureWorkspaceRecommendedExtensions": "配置建议的扩展(工作区)", - "deleteSure": "是否确定要卸载“{0}”?", + "disableAction": "禁用", + "disableAll": "全部禁用", + "disableAllWorkspace": "全部禁用(工作区)", + "disableAlwaysAction.label": "禁用", + "disableForWorkspaceAction": "工作区", + "disableForWorkspaceAction.label": "禁用(工作区)", + "disableGloballyAction": "始终", "enableAction": "启用", + "enableAll": "启用全部", + "enableAllWorkspace": "启用全部(工作区)", + "enableAlwaysAction.label": "启用", + "enableForWorkspaceAction": "工作区", + "enableForWorkspaceAction.label": "启用(工作区)", + "enableGloballyAction": "始终", "installAction": "安装", "installExtensions": "安装扩展", "installVSIX": "从 VSIX 安装...", "installing": "正在安装", "openExtensionsFolder": "打开扩展文件夹", - "postUninstallMessage": "已成功卸载 {0}。请重启以停用它。 ", - "restart": "若要启用此扩展,需要重启此 VS Code 窗口。\n\n是否继续?", - "restartNow": "立即重启", + "postDisableMessage": "重新加载此窗口以禁用“{0}”扩展程序?", + "postDisableTooltip": "重新加载以禁用", + "postEnableMessage": "重新加载此窗口以禁用“{0}”扩展程序?", + "postEnableTooltip": "重新加载以启用", + "postInstallMessage": "重新加载此窗口以激活“{0}”扩展程序?", + "postInstallTooltip": "重新加载以激活", + "postUninstallMessage": "重新加载此窗口以停用“{0}”扩展程序? ", + "postUninstallTooltip": "重新加载以停用", + "reloadAction": "重新加载", + "reloadNow": "立即重新加载", "showDisabledExtensions": "显示已禁用的扩展", "showInstalledExtensions": "显示已安装扩展", "showOutdatedExtensions": "显示过时扩展", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "显示推荐的扩展", "showWorkspaceRecommendedExtensions": "显示工作区建议的扩展名", "toggleExtensionsViewlet": "显示扩展", - "uninstall": "卸载", + "uninstallAction": "卸载", "updateAction": "更新", "updateAll": "更新所有扩展" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/chs/src/vs/workbench/parts/git/node/git.lib.i18n.json index 80b697be3d3..b6ae41ce274 100644 --- a/i18n/chs/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "无法从 git 中打开文件", "fileBinaryError": "文件似乎是二进制文件,无法作为文档打开" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/html/browser/webview.i18n.json b/i18n/chs/src/vs/workbench/parts/html/browser/webview.i18n.json index 8b6ad71cd4e..44bbc60787b 100644 --- a/i18n/chs/src/vs/workbench/parts/html/browser/webview.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/html/browser/webview.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "devtools.webview": "开发人员:Web 视图工具" +} \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json b/i18n/chs/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json index 2aa0db5137a..fea458099b3 100644 --- a/i18n/chs/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorsAndWarnings": "{0} 错误和警告" + "errorsAndWarnings": "{0} 个错误和警告" } \ No newline at end of file diff --git a/i18n/chs/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/chs/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index 2ce547d0e46..d5e480a99e2 100644 --- a/i18n/chs/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "首先打开文本文件以转到行", "gotoLine": "转到行...", - "gotoLineColumnLabel": "转到行 {0} 和列 {1}", + "gotoLineColumnLabel": "转到行 {0} 和字符 {1}", "gotoLineHandlerAriaLabel": "键入要导航到的行号。", "gotoLineLabel": "转至行 {0}", "gotoLineLabelEmpty": "键入要导航到的行号", diff --git a/i18n/chs/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json b/i18n/chs/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json index 5880b27d650..e984c31502d 100644 --- a/i18n/chs/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json @@ -8,7 +8,7 @@ "array": "数组({0})", "boolean": "布尔值({0})", "cannotRunGotoSymbol": "首先打开文本文件以转到符号", - "cannotRunGotoSymbolInFile": "很遗憾,我们没有该文件的任何符号信息", + "cannotRunGotoSymbolInFile": "没有该文件的任何符号信息", "class": "类({0})", "entryAriaLabel": "{0},符号", "enum": "枚举({0})", diff --git a/i18n/chs/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/chs/src/vs/workbench/parts/update/electron-browser/update.i18n.json index ebd875e2739..1abb02c8a30 100644 --- a/i18n/chs/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/chs/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "立即下载", + "insiderBuilds": "每日的会员版本和发布!", "later": "稍后", + "license": "读取许可证", + "licenseChanged": "我们的许可条款已更改,请仔细浏览。", + "neverShowAgain": "不再显示", "noUpdatesAvailable": "当前没有可用的更新。", "read the release notes": "欢迎使用 {0} v{1}! 是否要阅读发布说明?", + "readmore": "了解详细信息", "releaseNotes": "发行说明", "showReleaseNotes": "显示发行说明", "thereIsUpdateAvailable": "存在可用更新。", diff --git a/i18n/cht/extensions/typescript/out/features/bufferSyncSupport.i18n.json b/i18n/cht/extensions/typescript/out/features/bufferSyncSupport.i18n.json index 0054200abda..2035cd3963b 100644 --- a/i18n/cht/extensions/typescript/out/features/bufferSyncSupport.i18n.json +++ b/i18n/cht/extensions/typescript/out/features/bufferSyncSupport.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "close": "關閉", + "doNotCheckAgain": "不要再檢查", + "moreInformation": "詳細資訊", + "updateTscCheck": "已將使用者設定 'typescript.check.tscVersion' 更新為 false", "versionMismatch": "版本不符! 全域 TSC ({0}) != VS Code 的語言服務 ({1})。可能會發生編譯不一致的錯誤" } \ No newline at end of file diff --git a/i18n/cht/extensions/typescript/package.i18n.json b/i18n/cht/extensions/typescript/package.i18n.json index 5d0c7a26fb5..e9880e63df2 100644 --- a/i18n/cht/extensions/typescript/package.i18n.json +++ b/i18n/cht/extensions/typescript/package.i18n.json @@ -4,28 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "configuration.typescript": "TypeScript", - "format.insertSpaceAfterCommaDelimiter": "定義逗號分隔符號後的空格處理", - "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "定義匿名函式之函式關鍵字後的空格處理", - "format.insertSpaceAfterKeywordsInControlFlowStatements": "定義控制流量陳述式內關鍵字後的空格處理", - "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "定義 JSX 運算式左括號與右括號間的空格處理。需要 TypeScript >= 2.0.6", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "定義左中括弧與非空白右中括弧間的空格處理", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "定義左括弧與非空白右括弧間的空格處理", - "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "定義範本字串左括號與右括號間的空格處理。需要 TypeScript >= 2.0.6", - "format.insertSpaceAfterSemicolonInForStatements": "定義 for 陳述式內分號後的空格處理", - "format.insertSpaceBeforeAndAfterBinaryOperators": "定義二元運算子後的空格處理", - "format.placeOpenBraceOnNewLineForControlBlocks": "定義是否將左大括弧放入控制區塊的新行", - "format.placeOpenBraceOnNewLineForFunctions": "定義是否將左大括弧放入函式的新行", + "configuration.typescript": "TypeScript。", + "format.insertSpaceAfterCommaDelimiter": "定義逗號分隔符號後的空格處理。", + "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "定義匿名函式之函式關鍵字後的空格處理。", + "format.insertSpaceAfterKeywordsInControlFlowStatements": "定義控制流程陳述式內關鍵字後的空格處理。", + "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "定義 JSX 運算式左右大括弧間的空格處理。需要 TypeScript >= 2.0.6。", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "定義左右非空白中括弧間的空格處理。", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "定義左右非空白括弧間的空格處理。", + "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "定義範本字串左右大括弧間的空格處理。需要 TypeScript >= 2.0.6。", + "format.insertSpaceAfterSemicolonInForStatements": " 定義 for 陳述式內分號後的空格處理。", + "format.insertSpaceBeforeAndAfterBinaryOperators": "定義二元運算子後的空格處理。", + "format.placeOpenBraceOnNewLineForControlBlocks": "定義是否將左大括弧放入控制區塊的新行。", + "format.placeOpenBraceOnNewLineForFunctions": "定義是否將左大括弧放入函式的新行。", + "javascript.format.enable": "啟用/停用預設 JavaScript 格式器。", "javascript.reloadProjects.title": "重新載入 JavaScript 專案", - "javascript.validate.enable": "啟用 / 停用 JavaScript 驗證", + "javascript.validate.enable": "啟用/停用 JavaScript 驗證。", "typescript.check.tscVersion": "請檢查全域安裝 TypeScript 編譯器 (例如 tsc) 是否不同於使用的 TypeScript 語言服務。", - "typescript.check.workspaceVersion": "請檢查 TypeScript 版本是否可在工作區中使用", - "typescript.experimentalAutomaticTypeAcquisition": "啟用自動取得類型。需要 TypeScript >= 2.0.6,並在變更後重新啟動。", + "typescript.check.workspaceVersion": "請檢查 TypeScript 版本是否可在工作區中使用。", + "typescript.disableAutomaticTypeAcquisition": "停用自動類型取得。需要 TypeScript >= 2.0.6,並需要在變更後重新啟動。", + "typescript.format.enable": "啟用/停用預設 TypeScript 格式器。", "typescript.reloadProjects.title": "重新載入 TypeScript 專案", "typescript.tsdk.desc": "指定資料夾路徑,其中包含要使用的 tsserver 和 lib*.d.ts 檔案。", "typescript.tsdk_version.desc": "指定 tsserver 版本。只有在未使用 npm 安裝 tsserver 時才需要。", "typescript.tsserver.experimentalAutoBuild": "啟用實驗性自動建置。需要 1.9 dev 或 2.x tsserver 版本,且在變更後必須重新啟動 VS Code。", - "typescript.tsserver.trace": "允許追蹤傳送到 TS 伺服器的訊息", + "typescript.tsserver.trace": "允許追蹤傳送到 TS 伺服器的訊息。", "typescript.useCodeSnippetsOnMethodSuggest.dec": "使用其參數簽章完成函式。", - "typescript.validate.enable": "啟用 / 停用 TypeScript 驗證" + "typescript.validate.enable": "啟用/停用 TypeScript 驗證。" } \ No newline at end of file diff --git a/i18n/cht/src/vs/code/electron-main/menus.i18n.json b/i18n/cht/src/vs/code/electron-main/menus.i18n.json index 8ff84e10894..76081fc9506 100644 --- a/i18n/cht/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/cht/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "結束(&&X)", "miFind": "尋找(&&F)", "miFindInFiles": "在檔案中尋找(&&I)", - "miFocusFirstGroup": "左側群組(&&L)", - "miFocusSecondGroup": "置中群組(&&C)", - "miFocusThirdGroup": "右側群組(&&R)", + "miFocusFirstGroup": "第一個群組(&&F)", + "miFocusSecondGroup": "第二個群組(&&S)", + "miFocusThirdGroup": "第三個群組(&&T)", "miForward": "轉寄(&&F)", "miGotoDefinition": "移至定義(&&D)", "miGotoFile": "移至檔案(&&F)...", "miGotoLine": "移至行(&&L)...", "miGotoSymbolInFile": "前往檔案中的符號(&&S)...", "miGotoSymbolInWorkspace": "前往工作區中的符號(&&W)...", + "miHideStatusbar": "隱藏狀態列(&&H)", "miInstallingUpdate": "正在安裝更新...", - "miLicense": "檢視授權(&&V)", + "miIntroductoryVideos": "簡介影片(&&V)", + "miKeyboardShortcuts": "鍵盤快速鍵參考(&&K)", + "miLicense": "檢視授權(&&L)", "miMarker": "問題(&&P)", - "miMoveSidebar": "移動提要欄位(&&M)", + "miMoveSidebarLeft": "將提要欄位左移(&&M)", + "miMoveSidebarRight": "將提要欄位右移(&&M)", "miNewFile": "新增檔案(&&N)", "miNewWindow": "開新視窗(&&N)", "miNextEditor": "下一個編輯器(&&N)", @@ -84,11 +88,13 @@ "miSelectAll": "全選(&&S)", "miSelectColorTheme": "色彩佈景主題(&&C)", "miSelectIconTheme": "檔案圖示佈景主題(&&I)", + "miShowStatusbar": "顯示狀態列(&&S)", "miSplitEditor": "分割編輯器(&&E)", "miSwitchEditor": "切換編輯器(&&E)", "miSwitchGroup": "切換群組(&&G)", "miToggleDebugConsole": "偵錯主控台(&&B)", "miToggleDevTools": "切換開發人員工具(&&T)", + "miToggleEditorLayout": "切換編輯器群組配置(&&L)", "miToggleFullScreen": "切換全螢幕(&&F)", "miToggleIntegratedTerminal": "整合式終端機(&&I)", "miToggleMenuBar": "切換功能表列(&&B)", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "切換&&控制字元", "miToggleRenderWhitespace": "切換轉譯空白字元(&&R)", "miToggleSidebar": "切換提要欄位(&&T)", - "miToggleStatusbar": "切換狀態列(&&T)", "miToggleWordWrap": "切換自動換行(&&W)", "miTwitter": "加入我們的 Twitter(&&J)", "miUndo": "復原(&&U)", diff --git a/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json index 43e0a7cb1b1..181a3c2bcfb 100644 --- a/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/cht/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "控制游標樣式,接受的值為 'block'、'line' 和 'underline'", "detectIndentation": "開啟檔案時,會依據檔案內容來偵測 `editor.tabSize` 及 `editor.insertSpaces`。", "editorConfigurationTitle": "編輯器", + "emptySelectionClipboard": "控制複製時不選取任何項目是否會複製目前程式行。", "folding": "控制編輯器是否已啟用程式碼摺疊功能", "fontFamily": "控制字型家族。", "fontLigatures": "啟用連字字型", @@ -23,7 +24,7 @@ "insertSpaces": "在按 Tab 時插入空格。當 `editor.detectIndentation` 已開啟時,會根據檔案內容覆寫此設定。", "insertSpaces.errorMessage": "必須是 'boolean'。請注意,值 \"auto\" 已由 `editor.detect Indentation` 設定取代。", "lineHeight": "控制行高。使用 0 會從 fontSize 計算 lineHeight。", - "lineNumbers": "控制是否顯示行號", + "lineNumbers": "控制行號顯示。可能的值有 'on'、'off' 及 'relative'。'relative' 會從目前的資料指標位置顯示行數。", "mouseWheelScrollSensitivity": "滑鼠滾輪捲動事件的 'deltaX' 與 'deltaY' 所使用的乘數", "mouseWheelZoom": "使用滑鼠滾輪並按住 Ctrl 時,縮放編輯器的字型", "overviewRulerLanes": "控制可在概觀尺規中相同位置顯示的裝飾項目數", diff --git a/i18n/cht/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/cht/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index 7086aa8650b..dfab6ceed39 100644 --- a/i18n/cht/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "顯示協助工具說明", - "introMsg": "感謝您試用 VSCode 的實驗協助工具選項。", + "introMsg": "感謝您試用 VS Code 的協助工具選項。", "outroMsg": "您可以按 Esc 鍵來解除此工具提示並返回編輯器。", "status": "狀態:", - "tabFocusModeOffMsg": "在此編輯器中按 Tab 鍵會插入定位字元。按 {0} 可切換此行為。", - "tabFocusModeOffMsgNoKb": "在此編輯器中按 Tab 鍵會將焦點移至下一個可設定焦點的元素。目前無法透過按鍵繫結關係觸發命令 {0}。", - "tabFocusModeOnMsg": "在此編輯器中按 Tab 鍵會將焦點移至下一個可設定焦點的元素。按 {0} 可切換此行為。", - "tabFocusModeOnMsgNoKb": "在此編輯器中按 Tab 鍵會將焦點移至下一個可設定焦點的元素。目前無法透過按鍵繫結關係觸發命令 {0}。" + "tabFocusModeOffMsg": "在目前的編輯器中按 Tab 鍵會插入定位字元。按 {0} 可切換此行為。", + "tabFocusModeOffMsgNoKb": "在目前的編輯器中按 Tab 鍵會插入定位字元。命令 {0} 目前無法由按鍵繫結關係觸發。", + "tabFocusModeOnMsg": "在目前的編輯器中按 Tab 鍵會將焦點移至下一個可設定焦點的元素。按 {0} 可切換此行為。", + "tabFocusModeOnMsgNoKb": "在目前的編輯器中按 Tab 鍵會將焦點移至下一個可設定焦點的元素。命令 {0} 目前無法由按鍵繫結關係觸發。" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/cht/src/vs/editor/contrib/format/common/formatActions.i18n.json index 2b299139b69..833ea105532 100644 --- a/i18n/cht/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/cht/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "格式化程式碼" + "formatDocument.label": "將文件格式化", + "formatSelection.label": "將選取項目格式化" } \ No newline at end of file diff --git a/i18n/cht/src/vs/editor/node/textMate/TMSyntax.i18n.json b/i18n/cht/src/vs/editor/node/textMate/TMSyntax.i18n.json index 46fac1bfe93..9262fa60053 100644 --- a/i18n/cht/src/vs/editor/node/textMate/TMSyntax.i18n.json +++ b/i18n/cht/src/vs/editor/node/textMate/TMSyntax.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.embeddedLanguages": "`contributes.{0}.embeddedLanguages` 中的值無效。必須是從範圍名稱到語言的物件對應。提供的值: {1}", "invalid.injectTo": "`contributes.{0}.injectTo` 中的值無效。必須是語言範圍名稱的陣列。提供的值: {1}", "invalid.language": "`contributes.{0}.language` 中的不明語言。提供的值: {1}", "invalid.path.0": "`contributes.{0}.path` 中的預期字串。提供的值: {1}", "invalid.path.1": "要包含在擴充功能資料夾 ({2}) 中的預期 `contributes.{0}.path` ({1})。這可能會使擴充功能無法移植。", "invalid.scopeName": "`contributes.{0}.scopeName` 中的預期字串。提供的值: {1}", "vscode.extension.contributes.grammars": "提供 textmate 權杖化工具。", + "vscode.extension.contributes.grammars.embeddedLanguages": "如果此文法包含內嵌語言,即為範圍名稱到語言識別碼的對應。", "vscode.extension.contributes.grammars.injectTo": "要插入此文法的語言範圍名稱清單。", "vscode.extension.contributes.grammars.language": "要予以提供此語法的語言識別碼。", "vscode.extension.contributes.grammars.path": "tmLanguage 檔案的路徑。此路徑是擴充功能資料夾的相對路徑,而且一般會以 './syntaxes/' 開頭。", diff --git a/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 85318dcd3d0..0b9a6b0f864 100644 --- a/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/cht/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "取消", "doNotInstall": "否", "install": "是", "installDependeciesConfirmation": "安裝 '{0}' 也會安裝其相依性。要繼續嗎?", @@ -11,6 +12,14 @@ "invalidName": "擴充功能無效: 資訊清單名稱不相符。", "invalidPublisher": "擴充功能無效: 資訊清單發行者不相符。", "invalidVersion": "擴充功能無效: 資訊清單版本不相符。", + "multipleDependentsError": "無法將延伸模組 '{0}' 解除安裝。其為 '{1}'、'{2}' 及其他延伸模組的相依對象。", "notExists": "找不到擴充功能", - "restartCode": "請先重新啟動 Code,再重新安裝 {0}。" + "ok": "確定", + "restartCode": "請先重新啟動 Code,再重新安裝 {0}。", + "singleDependentError": "無法將延伸模組 '{0}' 解除安裝。其為延伸模組 '{1}' 的相依對象。", + "twoDependentsError": "無法將延伸模組 '{0}' 解除安裝。其為延伸模組 '{1}' 及 '{2}' 的相依對象。", + "uninstallAll": "全部", + "uninstallConfirmation": "確定要將 '{0}' 解除安裝嗎?", + "uninstallDependeciesConfirmation": "只要將 '{0}' 解除安裝,或要包含其相依性?", + "uninstallOnly": "只有" } \ No newline at end of file diff --git a/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 9b60780a6f4..368d02bfa26 100644 --- a/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/cht/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "屬性 `{0}` 可以省略或必須屬於 `string[]` 類型", - "extensionDescription.activationEvents2": "屬性 `{0}` 和 `{1}` 必須同時指定或同時忽略", - "extensionDescription.empty": "得到空白擴充功能描述", - "extensionDescription.engines": "屬性 '{0}' 為強制項目且必須屬於 `object` 類型", - "extensionDescription.engines.vscode": "屬性 '{0}' 為強制項目且必須屬於 `string` 類型", - "extensionDescription.extensionDependencies": "屬性 `{0}` 可以省略或必須屬於 `string[]` 類型", - "extensionDescription.main1": "屬性 `{0}` 可以省略或必須屬於 `string` 類型", - "extensionDescription.main2": "`main` ({0}) 必須包含在擴充功能的資料夾 ({1}) 中。這可能會使擴充功能無法移植。", - "extensionDescription.main3": "屬性 `{0}` 和 `{1}` 必須同時指定或同時忽略", - "extensionDescription.name": "屬性 '{0}' 為強制項目且必須屬於 `string` 類型", - "extensionDescription.publisher": "屬性 '{0}' 為強制項目且必須屬於 `string` 類型", - "extensionDescription.version": "屬性 '{0}' 為強制項目且必須屬於 `string` 類型", "vscode.extension.activationEvents": "VS Code 擴充功能的啟動事件。", "vscode.extension.badges": "要顯示於 Marketplace 擴充頁面資訊看板的徽章陣列。", "vscode.extension.badges.description": "徽章描述。", @@ -24,6 +12,7 @@ "vscode.extension.categories": "VS Code 資源庫用來將擴充功能歸類的分類。", "vscode.extension.contributes": "此封裝所代表的所有 VS Code 擴充功能比重。", "vscode.extension.displayName": "VS Code 資源庫中使用的擴充功能顯示名稱。", + "vscode.extension.engines.vscode": "若是 VS Code 延伸模組,則指定與延伸模組相容的 VS Code 版本。不得為 *。例如: ^0.10.5 表示與最低 VS Code 版本 0.10.5 相容。", "vscode.extension.extensionDependencies": "其它擴充功能的相依性。擴充功能的識別碼一律為 ${publisher}.${name}。例如: vscode.csharp。", "vscode.extension.galleryBanner": "用於 VS Code Marketplace 的橫幅。", "vscode.extension.galleryBanner.color": "VS Code Marketplace 頁首的橫幅色彩。", diff --git a/i18n/cht/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/cht/src/vs/workbench/browser/actions/openSettings.i18n.json index d9d0c9e9665..a3f21c399d2 100644 --- a/i18n/cht/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "預設鍵盤快速鍵", "defaultKeybindingsHeader": "將按鍵組合放入您的按鍵組合檔案中加以覆寫。", "defaultName": "預設值", + "defaultSettingsEditor": "預設設定編輯器", "defaultSettingsHeader": "將設定放入您的設定檔中加以覆寫。", "defaultSettingsHeader2": "如需最常使用的設定,請參閱 http://go.microsoft.com/fwlink/?LinkId=808995。", "emptyKeybindingsHeader": "將您的按鍵組合放入此檔案中以覆寫預設值", diff --git a/i18n/cht/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/cht/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..104b6bc810a 100644 --- a/i18n/cht/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "水平編輯器群組配置", + "toggleEditorGroupLayout": "切換編輯器群組垂直/水平配置", + "verticalLayout": "垂直編輯器群組配置", + "view": "檢視" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 69f025a9708..2316d101596 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "顯示所有開啟的編輯器", "binaryDiffEditor": "二進位 Diff 編輯器", - "centerEditorGroupPicker": "在置中群組顯示編輯器", - "leftEditorGroupPicker": "在左側群組顯示編輯器", - "rightEditorGroupPicker": "在右側群組顯示編輯器", + "groupOnePicker": "在第一個群組顯示編輯器", + "groupThreePicker": "在第三個群組顯示編輯器", + "groupTwoPicker": "在第二個群組顯示編輯器", "textDiffEditor": "文字 Diff 編輯器", "textEditor": "文字編輯器", "view": "檢視" diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index f56eaf2138f..04f50061b7a 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "關閉其他編輯器", "evenEditorGroups": "均分編輯器群組寬度", "focusActiveEditorGroup": "聚焦使用中的編輯器群組", - "focusFirstEditorGroup": "聚焦左側編輯器群組", + "focusFirstEditorGroup": "聚焦第一個編輯器群組", "focusLastEditorInStack": "開啟群組中最後一個編輯器", "focusNextGroup": "聚焦下一個群組", "focusPreviousGroup": "聚焦上一個群組", - "focusSecondEditorGroup": "聚焦置中編輯器群組", - "focusThirdEditorGroup": "聚焦右側編輯器群組", + "focusSecondEditorGroup": "聚焦第二個編輯器群組", + "focusThirdEditorGroup": "聚焦第三個編輯器群組", "keepEditor": "保留編輯器", "maximizeEditor": "將編輯器群組最大化並隱藏側邊欄", "minimizeOtherEditorGroups": "將其他編輯器群組最小化", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "將編輯器群組向右移", "moveEditorLeft": "將編輯器左移", "moveEditorRight": "將編輯器右移", - "moveEditorToLeftGroup": "將編輯器移入左側群組中", - "moveEditorToRightGroup": "將編輯器移入右側群組中", + "moveEditorToNextGroup": "將編輯器移入下一個群組", + "moveEditorToPreviousGroup": "將編輯器移入上一個群組", "navigateEditorGroups": "在編輯器群組間導覽", "navigateEditorHistoryByInput": "從記錄中開啟上一個編輯器", "navigateNext": "向前", @@ -38,12 +38,11 @@ "openPreviousEditor": "開啟上一個編輯器", "openPreviousEditorInGroup": "開啟群組中上一個最近使用的編輯器", "openToSide": "開至側邊", - "removeFromEditorHistory": "從編輯器記錄中移除", "reopenClosedEditor": "重新開啟已關閉的編輯器", "showAllEditors": "顯示所有編輯器", - "showEditorsInCenterGroup": "在置中群組顯示編輯器", + "showEditorsInFirstGroup": "在第一個群組顯示編輯器", "showEditorsInGroup": "在群組顯示編輯器", - "showEditorsInLeftGroup": "在左側群組顯示編輯器", - "showEditorsInRightGroup": "在右側群組顯示編輯器", + "showEditorsInSecondGroup": "在第二個群組顯示編輯器", + "showEditorsInThirdGroup": "在第三個群組顯示編輯器", "splitEditor": "分割編輯器" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index 62de24ed2b8..b266b2cdbb8 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "置中", "editorOpenError": "無法開啟 '{0}': {1}。", - "leftGroup": "左", - "rightGroup": "右" + "groupOneHorizontal": "上", + "groupOneVertical": "左", + "groupThreeHorizontal": "下", + "groupThreeVertical": "右", + "groupTwoHorizontal": "置中", + "groupTwoVertical": "置中" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index 7a60536b262..29f43b8785e 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0},編輯器群組選擇器", "groupLabel": "群組: {0}", - "noOpenedEditors": "已開啟編輯器的清單目前為空白", + "noOpenedEditors": "開啟的編輯器清單在群組中目前為空白", + "noOpenedEditorsAllGroups": "開啟的編輯器清單目前為空白", "noResultsFound": "找不到任何相符的已開啟編輯器", "noResultsFoundInGroup": "在群組中找不到任何相符的已開啟編輯器" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/cht/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 671f57fcb27..fce1ecc8781 100644 --- a/i18n/cht/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/cht/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "選取行尾順序", "selectEncoding": "選取編碼", "selectLanguageMode": "選取語言模式", + "showLanguageExtensions": "在 Marketplace 搜尋延伸模組 '{0}'...", "singleSelection": "第 {0} 行,第 {1} 欄", "singleSelectionRange": "第 {0} 行,第 {1} 欄 (已選取 {2})", "spacesSize": "空格: {0}", diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index 7b0c12ea2a0..9c694b02908 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "程式只有在此條件為 true 時才會在此停止。請按 Enter 鍵接受,或按 Esc 鍵取消。", - "breakpointWidgetExpressionPlaceholder": "運算式評估為 true 時中斷", + "breakpointWidgetExpressionPlaceholder": "在運算式評估為 true 時中斷。按 'Enter' 鍵接受,按 'esc' 鍵取消。", "breakpointWidgetHitCountAriaLabel": "程式只會在符合叫用次數時於此處停止。按 Enter 鍵接受,或按 Escape 鍵取消。", - "breakpointWidgetHitCountPlaceholder": "符合叫用次數條件時中斷", + "breakpointWidgetHitCountPlaceholder": "符合叫用次數條件時中斷。按 'Enter' 鍵接受,按 'esc' 鍵取消。", "expression": "運算式", "hitCount": "叫用次數" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index 04a14b30539..d1ad377de67 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "偵錯: 新增條件中斷點...", "continueDebug": "繼續", "deactivateBreakpoints": "停用中斷點", - "debugActionLabelAndKeybinding": "{0} ({1})", "debugAddToWatch": "偵錯: 加入監看", "debugConsoleAction": "偵錯主控台", "debugEvaluate": "偵錯: 評估", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "停用所有中斷點", "disconnectDebug": "中斷連接", "editConditionalBreakpoint": "編輯中斷點...", + "editWatchExpression": "編輯運算式", "enableAllBreakpoints": "啟用所有中斷點", "launchJsonNeedsConfigurtion": "設定或修正 'launch.json'", "openLaunchJson": "開啟 {0}", @@ -32,7 +32,6 @@ "removeBreakpoint": "移除中斷點", "removeWatchExpression": "移除運算式", "renameFunctionBreakpoint": "重新命名函式中斷點", - "renameWatchExpression": "重新命名運算式", "restartDebug": "重新啟動", "restartFrame": "重新啟動框架", "runToCursor": "偵錯: 執行至游標處", diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index ade6af21004..776a393c75b 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "允許設定所有檔案的中斷點,無論延伸模組為何。", + "allowBreakpointsEverywhere": "允許在任何檔案設定中斷點", "debug": "偵錯", "debugCategory": "偵錯", "debugConfigurationTitle": "偵錯", "debugErrorEditor": "對錯誤偵錯", "debugPanel": "偵錯主控台", - "launchConfigDoesNotExist": "啟動設定 '{0}' 不存在。", - "openExplorerOnEnd": "自動於偵錯工作階段結束時開啟 Explorer Viewlet。", + "openExplorerOnEnd": "自動於偵錯工作階段結束時開啟 Explorer Viewlet", "toggleDebugPanel": "偵錯主控台", "toggleDebugViewlet": "顯示偵錯", "view": "檢視" diff --git a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json index e6f42a8412b..418944f284c 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json @@ -12,6 +12,7 @@ "functionBreakpointsNotSupported": "此偵錯類型不支援函式中斷點", "loadMoreStackFrames": "載入更多堆疊框架", "paused": "已暫停", + "process": "處理序", "running": "正在執行", "stackFrameAriaLabel": "堆疊框架 {0} 第 {1} {2} 行,呼叫堆疊,偵錯", "thread": "執行緒", diff --git a/i18n/cht/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/cht/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index ff79c8c7c2d..ac2d67bd947 100644 --- a/i18n/cht/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "debugConfigurationNames": "會隨這項「複合」組態啟動的組態。只在此組態的類型為「複合」採用。", "debugLinuxConfiguration": "Linux 特定的啟動設定屬性。", "debugName": "組態的名稱; 出現在啟動組態下拉式功能表中。", "debugOSXConfiguration": "OS X 特定的啟動設定屬性。", diff --git a/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 52e04f418b7..f3f7f33d0a4 100644 --- a/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "只有在工作區資料夾中才能使用建議。", "OpenExtensionsFile.failed": "無法在 '.vscode' 資料夾 ({0}) 中建立 'extensions.json' 檔案。", - "OpenGlobalExtensionsStorageFile.failed": "無法在 '{0}' 資料夾中建立 'extensions.json' 檔案 ({1})。", + "Uninstalling": "正在解除安裝", "builtin": "內建", "clearExtensionsInput": "清除擴充功能輸入", "configureWorkspaceRecommendedExtensions": "設定建議的延伸模組 (工作區)", - "deleteSure": "確定要解除安裝 '{0}' 嗎?", + "disableAction": "停用", + "disableAll": "全部停用", + "disableAllWorkspace": "全部停用 (工作區)", + "disableAlwaysAction.label": "停用", + "disableForWorkspaceAction": "工作區", + "disableForWorkspaceAction.label": "停用 (工作區)", + "disableGloballyAction": "永遠", "enableAction": "啟用", + "enableAll": "全部啟用", + "enableAllWorkspace": "全部啟用 (工作區)", + "enableAlwaysAction.label": "啟用", + "enableForWorkspaceAction": "工作區", + "enableForWorkspaceAction.label": "啟用 (工作區)", + "enableGloballyAction": "永遠", "installAction": "安裝", "installExtensions": "安裝擴充功能", "installVSIX": "從 VSIX 安裝...", "installing": "正在安裝", "openExtensionsFolder": "開啟擴充功能資料夾", - "postUninstallMessage": "已成功將 '{0}' 解除安裝。請重新啟動加以停用。", - "restart": "為了啟用此擴充功能,必須重新啟動此 VS Code 視窗。\n\n要繼續嗎?", - "restartNow": "立即重新啟動", + "postDisableMessage": "要重新載入此視窗以停用 '{0}' 延伸模組嗎?", + "postDisableTooltip": "重新載入以停用", + "postEnableMessage": "要重新載入此視窗以啟用 '{0}' 延伸模組嗎?", + "postEnableTooltip": "重新載入以啟用", + "postInstallMessage": "要重新載入此視窗以啟動 '{0}' 延伸模組嗎?", + "postInstallTooltip": "重新載入以啟動", + "postUninstallMessage": "要重新載入此視窗以停用 '{0}' 延伸模組嗎?", + "postUninstallTooltip": "重新載入以停用", + "reloadAction": "重新載入", + "reloadNow": "立即重新載入", "showDisabledExtensions": "顯示停用的延伸模組", "showInstalledExtensions": "顯示安裝的擴充功能", "showOutdatedExtensions": "顯示過期的擴充功能", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "顯示建議的擴充功能", "showWorkspaceRecommendedExtensions": "顯示工作區的建議擴充功能", "toggleExtensionsViewlet": "顯示擴充功能", - "uninstall": "解除安裝", + "uninstallAction": "解除安裝", "updateAction": "更新", "updateAll": "更新所有擴充功能" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/cht/src/vs/workbench/parts/git/node/git.lib.i18n.json index 067f2923a48..4c4883aa515 100644 --- a/i18n/cht/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "無法從 git 開啟檔案", "fileBinaryError": "檔案似乎是二進位檔,因此無法當做文字開啟" } \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/html/browser/webview.i18n.json b/i18n/cht/src/vs/workbench/parts/html/browser/webview.i18n.json index 8b6ad71cd4e..b28cfae4deb 100644 --- a/i18n/cht/src/vs/workbench/parts/html/browser/webview.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/html/browser/webview.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "devtools.webview": "開發人員: Web 檢視工具" +} \ No newline at end of file diff --git a/i18n/cht/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/cht/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index e3851c5bd04..9706859750a 100644 --- a/i18n/cht/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "先開啟文字檔以移至某一行", "gotoLine": "移至行...", - "gotoLineColumnLabel": "移至行 {0} 和資料行 {1}", + "gotoLineColumnLabel": "移至行 {0} 和字元 {1}", "gotoLineHandlerAriaLabel": "輸入要瀏覽的行號。", "gotoLineLabel": "移至第 {0} 行", "gotoLineLabelEmpty": "輸入要瀏覽的行號", diff --git a/i18n/cht/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json b/i18n/cht/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json index f8897c513f6..6a26931715d 100644 --- a/i18n/cht/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json @@ -8,7 +8,7 @@ "array": "陣列 ({0})", "boolean": "布林值 ({0})", "cannotRunGotoSymbol": "先開啟文字檔以移至某一個符號", - "cannotRunGotoSymbolInFile": "很抱歉,我們沒有此檔案的符號資訊", + "cannotRunGotoSymbolInFile": "檔案沒有任何符號資訊", "class": "類別 ({0})", "entryAriaLabel": "{0},符號", "enum": "列舉 ({0})", diff --git a/i18n/cht/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/cht/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 8e7812a2f26..658ceed1296 100644 --- a/i18n/cht/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/cht/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "立即下載", + "insiderBuilds": "每日都有測試人員組建及版本!", "later": "稍後", + "license": "閱讀授權", + "licenseChanged": "授權條款已有所變更,請仔細閱讀。", + "neverShowAgain": "不要再顯示", "noUpdatesAvailable": "目前沒有可用的更新。", "read the release notes": "歡迎使用 {0} v{1}! 您要閱讀版本資訊嗎?", + "readmore": "閱讀其他資訊", "releaseNotes": "版本資訊", "showReleaseNotes": "顯示版本資訊", "thereIsUpdateAvailable": "已有更新可用。", diff --git a/i18n/deu/extensions/typescript/out/features/bufferSyncSupport.i18n.json b/i18n/deu/extensions/typescript/out/features/bufferSyncSupport.i18n.json index fef7c40a2aa..6ee5de399fe 100644 --- a/i18n/deu/extensions/typescript/out/features/bufferSyncSupport.i18n.json +++ b/i18n/deu/extensions/typescript/out/features/bufferSyncSupport.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "close": "Schließen", + "doNotCheckAgain": "Nicht erneut überprüfen", + "moreInformation": "Weitere Informationen", + "updateTscCheck": "Die Benutzereinstellung \"typescript.check.tscVersion\" wurde zu FALSE aktualisiert.", "versionMismatch": "Versionskonflikt zwischen dem globalen TSC ({0}) und dem Sprachdienst von VS Code ({1}). Dies kann zu Kompilierungsfehlern aufgrund von Inkonsistenzen führen." } \ No newline at end of file diff --git a/i18n/deu/extensions/typescript/package.i18n.json b/i18n/deu/extensions/typescript/package.i18n.json index 6cf7e6a8dc7..937eec157ec 100644 --- a/i18n/deu/extensions/typescript/package.i18n.json +++ b/i18n/deu/extensions/typescript/package.i18n.json @@ -4,28 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "configuration.typescript": "TypeScript", + "configuration.typescript": "TypeScript.", "format.insertSpaceAfterCommaDelimiter": "Definiert die Verarbeitung von Leerzeichen nach einem Kommatrennzeichen.", "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Definiert die Verarbeitung von Leerzeichen nach einem Funktionsschlüsselwort für anonyme Funktionen.", "format.insertSpaceAfterKeywordsInControlFlowStatements": "Definiert die Verarbeitung von Leerzeichen nach Schlüsselwörtern in einer Flusssteuerungsanweisung.", - "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Definiert die Verarbeitung von Leerzeichen nach öffnenden und vor schließenden geschweiften Klammern für JSX-Ausdrücke. Erfordert TypeScript >= 2.0.6", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Definiert die Verarbeitung von Leerzeichen nach dem Öffnen und vor dem Schließen einer nicht leeren eckigen Klammer.", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Definiert die Verarbeitung von Leerzeichen nach dem Öffnen und vor dem Schließen einer nicht leeren Klammer.", - "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Definiert die Verarbeitung von Leerzeichen nach öffnenden und vor schließenden geschweiften Klammern für Vorlagenzeichenfolgen. Erfordert TypeScript >= 2.0.6", + "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Definiert die Verarbeitung von Leerzeichen nach öffnenden und vor schließenden geschweiften Klammern für JSX-Ausdrücke. Erfordert TypeScript >= 2.0.6.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Definiert die Verarbeitung von Leerzeichen nach öffnenden und vor schließenden nicht leeren eckigen Klammern.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Definiert die Verarbeitung von Leerzeichen nach öffnenden und vor schließenden nicht leeren runden Klammern.", + "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Definiert die Verarbeitung von Leerzeichen nach öffnenden und vor schließenden geschweiften Klammern für Vorlagenzeichenfolgen. Erfordert TypeScript >= 2.0.6.", "format.insertSpaceAfterSemicolonInForStatements": " Definiert die Verarbeitung von Leerzeichen nach einem Semikolon in einer for-Anweisung.", "format.insertSpaceBeforeAndAfterBinaryOperators": "Definiert die Verarbeitung von Leerzeichen nach einem binären Operator.", - "format.placeOpenBraceOnNewLineForControlBlocks": "Definiert, ob eine öffnende geschweifte Klammer in eine neue Zeile für Kontrollblöcke eingefügt wird.", - "format.placeOpenBraceOnNewLineForFunctions": "Definiert, ob eine öffnende geschweifte Klammer in eine neue Zeile für Funktionen eingefügt wird.", + "format.placeOpenBraceOnNewLineForControlBlocks": "Definiert, ob eine öffnende geschweifte Klammer für Kontrollblöcke in eine neue Zeile eingefügt wird.", + "format.placeOpenBraceOnNewLineForFunctions": "Definiert, ob eine öffnende geschweifte Klammer für Funktionen in eine neue Zeile eingefügt wird.", + "javascript.format.enable": "Standardmäßigen JavaScript-Formatierer aktivieren/deaktivieren.", "javascript.reloadProjects.title": "JavaScript-Projekt erneut laden", - "javascript.validate.enable": "JavaScript-Überprüfung aktivieren/deaktivieren", + "javascript.validate.enable": "JavaScript-Überprüfung aktivieren/deaktivieren.", "typescript.check.tscVersion": "Überprüfen, ob sich ein global installierter TypeScript-Compiler (z. B. tsc) vom verwendeten TypeScript-Sprachdienst unterscheidet.", - "typescript.check.workspaceVersion": "Überprüfen, ob eine TypeScript-Version im Arbeitsbereich verfügbar ist", - "typescript.experimentalAutomaticTypeAcquisition": "Aktiviert die automatische Typerfassung. Erfordert TypeScript >= 2.0.6 und einen Neustart nach der Änderung.", + "typescript.check.workspaceVersion": "Überprüfen Sie, ob eine TypeScript-Version im Arbeitsbereich verfügbar ist.", + "typescript.disableAutomaticTypeAcquisition": "Deaktiviert die automatische Typerfassung. Erfordert TypeScript >= 2.0.6 und einen Neustart nach der Änderung.", + "typescript.format.enable": "Standardmäßigen TypeScript-Formatierer aktivieren/deaktivieren.", "typescript.reloadProjects.title": "TypeScript-Projekt erneut laden", "typescript.tsdk.desc": "Gibt den Ordnerpfad mit den zu verwendenden tsserver- und lib*.d.ts-Dateien an.", "typescript.tsdk_version.desc": "Gibt die Version von tsserver an. Nur erforderlich, wenn der tsserver nicht mithilfe von npm installiert wird.", "typescript.tsserver.experimentalAutoBuild": "Ermöglicht experimentelle automatische Buildvorgänge. Erfordert Version 1.9 dev oder 2.x tsserver sowie einen Neustart von VS Code nach der Änderung.", "typescript.tsserver.trace": "Aktiviert die Nachverfolgung von an den TS-Server gesendeten Nachrichten.", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Vervollständigen Sie Funktionen mit deren Parametersignatur.", - "typescript.validate.enable": "TypeScript-Überprüfung aktivieren/deaktivieren" + "typescript.validate.enable": "TypeScript-Überprüfung aktivieren/deaktivieren." } \ No newline at end of file diff --git a/i18n/deu/src/vs/code/electron-main/menus.i18n.json b/i18n/deu/src/vs/code/electron-main/menus.i18n.json index 5af85bba89e..1cb0ef1803b 100644 --- a/i18n/deu/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/deu/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "&&Beenden", "miFind": "&&Suchen", "miFindInFiles": "&&In Dateien suchen", - "miFocusFirstGroup": "&&Linke Gruppe", - "miFocusSecondGroup": "&&Mittlere Gruppe", - "miFocusThirdGroup": "&&Rechte Gruppe", + "miFocusFirstGroup": "&&Erste Gruppe", + "miFocusSecondGroup": "&&Zweite Gruppe", + "miFocusThirdGroup": "&&Dritte Gruppe", "miForward": "&&Weiterleiten", "miGotoDefinition": "Gehe &&zu Definition", "miGotoFile": "Gehe zu &&Datei...", "miGotoLine": "Gehe zu Zei&&le...", "miGotoSymbolInFile": "Gehe zu &&Symbol in Datei...", "miGotoSymbolInWorkspace": "Zu Symbol im &&Arbeitsbereich wechseln...", + "miHideStatusbar": "&&Statusleiste ausblenden", "miInstallingUpdate": "Update wird installiert...", + "miIntroductoryVideos": "&&Einführungsvideos", + "miKeyboardShortcuts": "&&Referenz für Tastenkombinationen", "miLicense": "&&Lizenz anzeigen", "miMarker": "&&Probleme", - "miMoveSidebar": "&&Randleiste verschieben", + "miMoveSidebarLeft": "&&Seitenleiste nach links verschieben", + "miMoveSidebarRight": "&&Seitenleiste nach rechts verschieben", "miNewFile": "&&Neue Datei", "miNewWindow": "&&Neues Fenster", "miNextEditor": "&&Nächster Editor", @@ -84,11 +88,13 @@ "miSelectAll": "&&Alles auswählen", "miSelectColorTheme": "&&Farbdesign", "miSelectIconTheme": "Datei- &&Symboldesign", + "miShowStatusbar": "&&Statusleiste anzeigen", "miSplitEditor": "&&Editor teilen", "miSwitchEditor": "&&Editor wechseln", "miSwitchGroup": "&&Gruppe wechseln", "miToggleDebugConsole": "De&&bugkonsole", "miToggleDevTools": "&&Entwicklungstools umschalten", + "miToggleEditorLayout": "&&Layout für Editor-Gruppe umschalten", "miToggleFullScreen": "&&Vollbild umschalten", "miToggleIntegratedTerminal": "&&Integriertes Terminal", "miToggleMenuBar": "Men&&üleiste umschalten", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "&&Steuerzeichen umschalten", "miToggleRenderWhitespace": "&&Rendern von Leerzeichen umschalten", "miToggleSidebar": "&&Randleiste umschalten", - "miToggleStatusbar": "&&Statusleiste umschalten", "miToggleWordWrap": "&&Zeilenumbruch umschalten", "miTwitter": "&&Twitter", "miUndo": "&&Rückgängig", diff --git a/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json index 26038738af5..58b2767b593 100644 --- a/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/deu/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "Steuert den Cursorstil. Gültige Werte sind \"block\", \"line\" und \"underline\".", "detectIndentation": "Beim Öffnen einer Datei werden \"editor.tabSize\" und \"editor.insertSpaces\" basierend auf den Dateiinhalten erkannt.", "editorConfigurationTitle": "Editor", + "emptySelectionClipboard": "Steuert, ob ein Kopiervorgang ohne Auswahl die aktuelle Zeile kopiert.", "folding": "Steuert, ob für den Editor Codefaltung aktiviert ist.", "fontFamily": "Steuert die Schriftfamilie.", "fontLigatures": "Aktiviert Schriftartligaturen.", @@ -23,7 +24,7 @@ "insertSpaces": "Fügt beim Drücken der TAB-TASTE Leerzeichen ein. Diese Einstellung wird basierend auf dem Inhalt der Datei überschrieben, wenn \"editor.detectIndentation\" aktiviert ist.", "insertSpaces.errorMessage": "\"boolean\" wurde erwartet. Beachten Sie, dass der Wert \"auto\" durch die Einstellung \"editor.detectIndentation\" ersetzt wurde.", "lineHeight": "Steuert die Zeilenhöhe. Verwenden Sie 0, um LineHeight aus der FontSize-Angabe zu berechnen.", - "lineNumbers": "Steuert die Sichtbarkeit der Zeilennummern.", + "lineNumbers": "Steuert die Anzeige von Zeilennummern. Mögliche Werte sind \"Ein\", \"Aus\" und \"Relativ\". \"Relativ\" zeigt die Zeilenanzahl ab der aktuellen Cursorposition.", "mouseWheelScrollSensitivity": "Ein Multiplikator, der für die Mausrad-Bildlaufereignisse \"deltaX\" und \"deltaY\" verwendet werden soll.", "mouseWheelZoom": "Schriftart des Editors vergrößern, wenn das Mausrad verwendet und die STRG-TASTE gedrückt wird", "overviewRulerLanes": "Steuert die Anzahl von Dekorationen, die an derselben Position im Übersichtslineal angezeigt werden.", diff --git a/i18n/deu/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/deu/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index e7e5d37b71f..6906daa0cdf 100644 --- a/i18n/deu/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "Hilfe zur Barrierefreiheit anzeigen", - "introMsg": "Vielen Dank, dass Sie die experimentellen Optionen für Barrierefreiheit von VS Code testen.", + "introMsg": "Vielen Dank, dass Sie die Optionen für Barrierefreiheit von VS Code testen.", "outroMsg": "Sie können diese QuickInfo schließen und durch Drücken von ESC zum Editor zurückkehren.", "status": "Status:", - "tabFocusModeOffMsg": "Durch Drücken der TAB-TASTE in diesem Editor wird das Tabstoppzeichen eingefügt. Schalten Sie dieses Verhalten um, indem Sie {0} drücken.", - "tabFocusModeOffMsgNoKb": "Durch Drücken der TAB-TASTE in diesem Editor wird der Fokus in das nächste Element verschoben, das den Fokus erhalten kann. Der Befehl {0} kann zurzeit nicht durch eine Tastenbindung ausgelöst werden.", - "tabFocusModeOnMsg": "Durch Drücken der TAB-TASTE in diesem Editor wird der Fokus in das nächste Element verschoben, das den Fokus erhalten kann. Schalten Sie dieses Verhalten um, indem Sie {0} drücken.", - "tabFocusModeOnMsgNoKb": "Durch Drücken der TAB-TASTE in diesem Editor wird der Fokus in das nächste Element verschoben, das den Fokus erhalten kann. Der Befehl {0} kann zurzeit nicht durch eine Tastenbindung ausgelöst werden." + "tabFocusModeOffMsg": "Durch Drücken der TAB-TASTE im aktuellen Editor wird das Tabstoppzeichen eingefügt. Schalten Sie dieses Verhalten um, indem Sie {0} drücken.", + "tabFocusModeOffMsgNoKb": "Durch Drücken der TAB-TASTE im aktuellen Editor wird das Tabstoppzeichen eingefügt. Der {0}-Befehl kann zurzeit nicht durch eine Tastenzuordnung ausgelöst werden.", + "tabFocusModeOnMsg": "Durch Drücken der TAB-TASTE im aktuellen Editor wird der Fokus in das nächste Element verschoben, das den Fokus erhalten kann. Schalten Sie dieses Verhalten um, indem Sie {0} drücken.", + "tabFocusModeOnMsgNoKb": "Durch Drücken der TAB-TASTE im aktuellen Editor wird der Fokus in das nächste Element verschoben, das den Fokus erhalten kann. Der {0}-Befehl kann zurzeit nicht durch eine Tastenzuordnung ausgelöst werden." } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/deu/src/vs/editor/contrib/format/common/formatActions.i18n.json index d3b6c6e2207..12ee0f94076 100644 --- a/i18n/deu/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/deu/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "Code formatieren" + "formatDocument.label": "Dokument formatieren", + "formatSelection.label": "Auswahl formatieren" } \ No newline at end of file diff --git a/i18n/deu/src/vs/editor/node/textMate/TMSyntax.i18n.json b/i18n/deu/src/vs/editor/node/textMate/TMSyntax.i18n.json index 2561753b38b..41c68b1dcc1 100644 --- a/i18n/deu/src/vs/editor/node/textMate/TMSyntax.i18n.json +++ b/i18n/deu/src/vs/editor/node/textMate/TMSyntax.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.embeddedLanguages": "Ungültiger Wert in \"contributes.{0}.embeddedLanguages\". Muss eine Objektzuordnung von Bereichsname zu Sprache sein. Angegebener Wert: {1}", "invalid.injectTo": "Ungültiger Wert in \"contributes.{0}.injectTo\". Es muss sich um ein Array von Sprachbereichsnamen handeln. Bereitgestellter Wert: {1}", "invalid.language": "Unbekannte Sprache in \"contributes.{0}.language\". Bereitgestellter Wert: {1}", "invalid.path.0": "In \"contributes.{0}.path\" wurde eine Zeichenfolge erwartet. Bereitgestellter Wert: {1}", "invalid.path.1": "Es wurde erwartet, dass \"contributes.{0}.path\" ({1}) im Ordner ({2}) der Extension enthalten ist. Dies führt ggf. dazu, dass die Extension nicht portierbar ist.", "invalid.scopeName": "In \"contributes.{0}.scopeName\" wurde eine Zeichenfolge erwartet. Bereitgestellter Wert: {1}", "vscode.extension.contributes.grammars": "Trägt TextMate-Tokenizer bei.", + "vscode.extension.contributes.grammars.embeddedLanguages": "Eine Zuordnung zwischen Bereichsname und Sprach-ID, wenn diese Grammatik eingebettete Sprachen enthält.", "vscode.extension.contributes.grammars.injectTo": "Die Liste der Sprachbereichsnamen, in die diese Grammatik injiziert wird.", "vscode.extension.contributes.grammars.language": "Der Sprachbezeichner, für den diese Syntax beigetragen wird.", "vscode.extension.contributes.grammars.path": "Der Pfad der tmLanguage-Datei. Der Pfad ist relativ zum Extensionordner und beginnt normalerweise mit \". /syntaxes/\".", diff --git a/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index a185f9cd95e..d576be4ddad 100644 --- a/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/deu/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "Abbrechen", "doNotInstall": "Nein", "install": "Ja", "installDependeciesConfirmation": "Durch das Installieren von \"{0}\" werden auch die abhängigen Komponenten installiert. Möchten Sie den Vorgang fortsetzen?", @@ -11,6 +12,14 @@ "invalidName": "Die Erweiterung ist ungültig: Manifestnamenkonflikt.", "invalidPublisher": "Die Erweiterung ist ungültig: Manifestherausgeberkonflikt.", "invalidVersion": "Die Erweiterung ist ungültig: Manifestversionskonflikt.", + "multipleDependentsError": "Die Erweiterung \"{0}\" kann nicht deinstalliert werden. Die Erweiterungen \"{1}\" und \"{2}\" sowie weitere hängen von dieser Erweiterung ab.", "notExists": "Die Erweiterung wurde nicht gefunden.", - "restartCode": "Bitte starten Sie Code vor der Neuinstallation von {0} neu." + "ok": "OK", + "restartCode": "Bitte starten Sie Code vor der Neuinstallation von {0} neu.", + "singleDependentError": "Die Erweiterung \"{0}\" kann nicht deinstalliert werden. Die Erweiterung \"{1}\" hängt von dieser Erweiterung ab.", + "twoDependentsError": "Die Erweiterung \"{0}\" kann nicht deinstalliert werden. Die Erweiterungen \"{1}\" und \"{2}\" hängen von dieser Erweiterung ab.", + "uninstallAll": "Alle", + "uninstallConfirmation": "Möchten Sie \"{0}\" deinstallieren?", + "uninstallDependeciesConfirmation": "Möchten Sie nur \"{0}\" oder auch die zugehörigen Abhängigkeiten deinstallieren?", + "uninstallOnly": "Nur" } \ No newline at end of file diff --git a/i18n/deu/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/deu/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index db963c9a252..a89119e98db 100644 --- a/i18n/deu/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/deu/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "Die Eigenschaft \"{0}\" kann ausgelassen werden oder muss vom Typ \"string[]\" sein.", - "extensionDescription.activationEvents2": "Die Eigenschaften \"{0}\" und \"{1}\" müssen beide angegeben oder beide ausgelassen werden.", - "extensionDescription.empty": "Es wurde eine leere Extensionbeschreibung abgerufen.", - "extensionDescription.engines": "Die Eigenschaft \"{0}\" ist erforderlich und muss vom Typ \"object\" sein.", - "extensionDescription.engines.vscode": "Die Eigenschaft \"{0}\" ist erforderlich. Sie muss vom Typ \"string\" sein.", - "extensionDescription.extensionDependencies": "Die Eigenschaft \"{0}\" kann ausgelassen werden oder muss vom Typ \"string[]\" sein.", - "extensionDescription.main1": "Die Eigenschaft \"{0}\" kann ausgelassen werden oder muss vom Typ \"string\" sein.", - "extensionDescription.main2": "Es wurde erwartet, dass \"main\" ({0}) im Ordner ({1}) der Extension enthalten ist. Dies führt ggf. dazu, dass die Extension nicht portierbar ist.", - "extensionDescription.main3": "Die Eigenschaften \"{0}\" und \"{1}\" müssen beide angegeben oder beide ausgelassen werden.", - "extensionDescription.name": "Die Eigenschaft \"{0}\" ist erforderlich. Sie muss vom Typ \"string\" sein.", - "extensionDescription.publisher": "Die Eigenschaft \"{0}\" ist erforderlich. Sie muss vom Typ \"string\" sein.", - "extensionDescription.version": "Die Eigenschaft \"{0}\" ist erforderlich. Sie muss vom Typ \"string\" sein.", "vscode.extension.activationEvents": "Aktivierungsereignisse für die VS Code-Extension.", "vscode.extension.badges": "Array aus Badges, die im Marketplace in der Seitenleiste auf der Seite mit den Erweiterungen angezeigt werden.", "vscode.extension.badges.description": "Eine Beschreibung für den Badge.", @@ -24,6 +12,7 @@ "vscode.extension.categories": "Die vom VS Code-Katalog zum Kategorisieren der Extension verwendeten Kategorien.", "vscode.extension.contributes": "Alle Beiträge der VS Code-Extension, die durch dieses Paket dargestellt werden.", "vscode.extension.displayName": "Der Anzeigename für die Extension, der im VS Code-Katalog verwendet wird.", + "vscode.extension.engines.vscode": "Gibt für VS Code-Erweiterungen die VS Code-Version an, mit der die Erweiterung kompatibel ist. Darf nicht \"*\" sein. Beispiel: ^0.10.5 gibt die Kompatibilität mit mindestens VS Code-Version 0.10.5 an.", "vscode.extension.extensionDependencies": "Abhängigkeiten von anderen Erweiterungen. Der Bezeichner einer Erweiterung ist immer ${publisher}.${name}, beispielsweise \"vscode.csharp\".", "vscode.extension.galleryBanner": "Das in VS Code Marketplace verwendete Banner.", "vscode.extension.galleryBanner.color": "Die Bannerfarbe für die Kopfzeile der VS Code Marketplace-Seite.", diff --git a/i18n/deu/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/deu/src/vs/workbench/browser/actions/openSettings.i18n.json index 5fede61d547..7a568fcebdf 100644 --- a/i18n/deu/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "Standard-Tastaturkurzbefehle", "defaultKeybindingsHeader": "Überschreiben Sie Tastenzuordnungen, indem Sie sie in die Tastenzuordnungsdatei einfügen.", "defaultName": "Standardeinstellungen", + "defaultSettingsEditor": "Standard-Editor für Einstellungen", "defaultSettingsHeader": "Überschreiben Sie Einstellungen, indem Sie sie in die Einstellungsdatei einfügen.", "defaultSettingsHeader2": "Unter http://go.microsoft.com/fwlink/?LinkId=808995 finden Sie die am häufigsten verwendeten Einstellungen.", "emptyKeybindingsHeader": "Platzieren Sie Ihre Tastenzuordnungen in dieser Datei, um die Standardwerte zu überschreiben.", diff --git a/i18n/deu/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/deu/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..eecec2ac66d 100644 --- a/i18n/deu/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "Horizontales Layout für Editor-Gruppe", + "toggleEditorGroupLayout": "Horizontales/Vertikales Layout für Editor-Gruppe umschalten", + "verticalLayout": "Vertikales Layout für Editor-Gruppe", + "view": "Anzeigen" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 96737d8e63e..18be445a7c6 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "Alle geöffneten Editoren anzeigen", "binaryDiffEditor": "Binärdiff-Editor", - "centerEditorGroupPicker": "Editoren in der zentralen Gruppe anzeigen", - "leftEditorGroupPicker": "Editoren in der linken Gruppe anzeigen", - "rightEditorGroupPicker": "Editoren in der rechten Gruppe anzeigen", + "groupOnePicker": "Editoren in erster Gruppe anzeigen", + "groupThreePicker": "Editoren in dritter Gruppe anzeigen", + "groupTwoPicker": "Editoren in zweiter Gruppe anzeigen", "textDiffEditor": "Textdiff-Editor", "textEditor": "Text-Editor", "view": "Anzeigen" diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 1034cb9cdfc..59804eb94e1 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "Andere Editoren schließen", "evenEditorGroups": "Gleichmäßige Breite der Editor-Gruppe", "focusActiveEditorGroup": "Fokus in aktiver Editor-Gruppe", - "focusFirstEditorGroup": "Fokus in linker Editor-Gruppe", + "focusFirstEditorGroup": "Fokus in erster Editor-Gruppe", "focusLastEditorInStack": "Letzten Editor in der Gruppe öffnen", "focusNextGroup": "Fokus in nächster Gruppe", "focusPreviousGroup": "Fokus in vorheriger Gruppe", - "focusSecondEditorGroup": "Fokus in mittlerer Editor-Gruppe", - "focusThirdEditorGroup": "Fokus in rechter Editor-Gruppe", + "focusSecondEditorGroup": "Fokus in zweiter Editor-Gruppe", + "focusThirdEditorGroup": "Fokus in dritter Editor-Gruppe", "keepEditor": "Editor beibehalten", "maximizeEditor": "Editor-Gruppe maximieren und Randleiste ausblenden", "minimizeOtherEditorGroups": "Andere Editor-Gruppen minimieren", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "Editor-Gruppe nach rechts verschieben", "moveEditorLeft": "Editor nach links verschieben", "moveEditorRight": "Editor nach rechts verschieben", - "moveEditorToLeftGroup": "Editor in Gruppe nach links verschieben", - "moveEditorToRightGroup": "Editor in Gruppe nach rechts verschieben", + "moveEditorToNextGroup": "Editor in nächste Gruppe verschieben", + "moveEditorToPreviousGroup": "Editor in vorherige Gruppe verschieben", "navigateEditorGroups": "Zwischen Editor-Gruppen navigieren", "navigateEditorHistoryByInput": "Vorherigen Editor aus Verlauf öffnen", "navigateNext": "Weiter", @@ -38,12 +38,11 @@ "openPreviousEditor": "Vorherigen Editor öffnen", "openPreviousEditorInGroup": "Vorherigen zuletzt verwendeten Editor in der Gruppe öffnen", "openToSide": "An der Seite öffnen", - "removeFromEditorHistory": "Aus Editor-Verlauf entfernen", "reopenClosedEditor": "Geschlossenen Editor erneut öffnen", "showAllEditors": "Alle Editoren anzeigen", - "showEditorsInCenterGroup": "Editoren in der zentralen Gruppe anzeigen", + "showEditorsInFirstGroup": "Editoren in erster Gruppe anzeigen", "showEditorsInGroup": "Editoren in der Gruppe anzeigen", - "showEditorsInLeftGroup": "Editoren in der linken Gruppe anzeigen", - "showEditorsInRightGroup": "Editoren in der rechten Gruppe anzeigen", + "showEditorsInSecondGroup": "Editoren in zweiter Gruppe anzeigen", + "showEditorsInThirdGroup": "Editoren in dritter Gruppe anzeigen", "splitEditor": "Editor teilen" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index e650349f5be..a29bb7277e3 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "Zentriert", "editorOpenError": "{0} kann nicht geöffnet werden: {1}", - "leftGroup": "Links", - "rightGroup": "Rechts" + "groupOneHorizontal": "Oben", + "groupOneVertical": "Links", + "groupThreeHorizontal": "Unten", + "groupThreeVertical": "Rechts", + "groupTwoHorizontal": "Zentriert", + "groupTwoVertical": "Zentriert" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index 99401433663..e3ed2d9c970 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0}, Editor-Gruppenauswahl", "groupLabel": "Gruppe: {0}", - "noOpenedEditors": "Die Liste der geöffneten Editoren ist zurzeit leer.", + "noOpenedEditors": "Die Liste der geöffneten Editoren in der Gruppe ist zurzeit leer.", + "noOpenedEditorsAllGroups": "Die Liste der geöffneten Editoren ist zurzeit leer.", "noResultsFound": "Es wurde kein übereinstimmender geöffneter Editor gefunden.", "noResultsFoundInGroup": "Es wurde kein übereinstimmender geöffneter Editor in der Gruppe gefunden." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/deu/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 967978e44b3..206cb0a17b4 100644 --- a/i18n/deu/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/deu/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "Zeilenendesequenz auswählen", "selectEncoding": "Codierung auswählen", "selectLanguageMode": "Sprachmodus auswählen", + "showLanguageExtensions": "Marketplace-Erweiterungen für \"{0}\" durchsuchen...", "singleSelection": "Zeile {0}, Spalte {1}", "singleSelectionRange": "Zeile {0}, Spalte {1} ({2} ausgewählt)", "spacesSize": "Leerzeichen: {0}", diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index d1e4d946b4d..904bd2badf8 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "Das Programm wird nur angehalten, wenn diese Bedingung erfüllt ist. Drücken Sie zum Akzeptieren die EINGABETASTE oder ESC, um den Vorgang abzubrechen.", - "breakpointWidgetExpressionPlaceholder": "Unterbrechen, wenn der Ausdruck als TRUE ausgewertet wird", + "breakpointWidgetExpressionPlaceholder": "Unterbrechen, wenn der Ausdruck als TRUE ausgewertet wird. EINGABETASTE zum Akzeptieren, ESC-TASTE zum Abbrechen.", "breakpointWidgetHitCountAriaLabel": "Das Programm wird nur angehalten, wenn die Bedingung für die Trefferanzahl erfüllt ist. Drücken Sie zum Akzeptieren die EINGABETASTE oder ESC, um den Vorgang abzubrechen.", - "breakpointWidgetHitCountPlaceholder": "Unterbrechen, wenn die Bedingung für die Trefferanzahl erfüllt ist", + "breakpointWidgetHitCountPlaceholder": "Unterbrechen, wenn die Bedingung für die Trefferanzahl erfüllt ist. EINGABETASTE zum Akzeptieren, ESC-TASTE zum Abbrechen.", "expression": "Ausdruck", "hitCount": "Trefferanzahl" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index 4e79dee8529..e749f49e977 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "Debuggen: Bedingten Haltepunkt hinzufügen...", "continueDebug": "Weiter", "deactivateBreakpoints": "Haltepunkte deaktivieren", - "debugActionLabelAndKeybinding": "{0} ({1})", "debugAddToWatch": "Debuggen: Zur Überwachung hinzufügen", "debugConsoleAction": "Debugging-Konsole", "debugEvaluate": "Debuggen: Auswerten", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "Alle Haltepunkte deaktivieren", "disconnectDebug": "Trennen", "editConditionalBreakpoint": "Haltepunkt bearbeiten...", + "editWatchExpression": "Ausdruck bearbeiten", "enableAllBreakpoints": "Alle Haltepunkte aktivieren", "launchJsonNeedsConfigurtion": "Konfigurieren oder reparieren Sie \"launch.json\".", "openLaunchJson": "{0} öffnen", @@ -32,7 +32,6 @@ "removeBreakpoint": "Haltepunkt entfernen", "removeWatchExpression": "Ausdruck entfernen", "renameFunctionBreakpoint": "Funktionshaltepunkt umbenennen", - "renameWatchExpression": "Ausdruck umbenennen", "restartDebug": "Neu starten", "restartFrame": "Frame neu starten", "runToCursor": "Debuggen: Ausführen bis Cursor", diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index 0d03c8ccd26..8b623e89f6c 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,13 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "Ermöglicht das Festlegen von Haltepunkten für alle Dateien, unabhängig von der Erweiterung.", + "allowBreakpointsEverywhere": "Ermöglicht das Festlegen von Haltepunkten für alle Dateien.", "debug": "Debuggen", "debugCategory": "Debuggen", "debugConfigurationTitle": "Debuggen", "debugErrorEditor": "Debuggingfehler", "debugPanel": "Debugging-Konsole", - "launchConfigDoesNotExist": "Die Startkonfiguration \"{0}\" ist nicht vorhanden.", "openExplorerOnEnd": "Hiermit wird am Ende einer Debugsitzung automatisch ein Explorer-Viewlet geöffnet.", "toggleDebugPanel": "Debugging-Konsole", "toggleDebugViewlet": "Debuggen anzeigen", diff --git a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json index 877b32257f1..707efb0d17e 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json @@ -12,6 +12,7 @@ "functionBreakpointsNotSupported": "Funktionshaltepunkte werden von diesem Debugtyp nicht unterstützt.", "loadMoreStackFrames": "Weitere Stapelrahmen laden", "paused": "Angehalten", + "process": "Prozess", "running": "Wird ausgeführt", "stackFrameAriaLabel": "Stapelrahmen {0} Zeile {1} {2}, Aufrufliste, Debuggen", "thread": "Thread", diff --git a/i18n/deu/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/deu/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index af806fc345a..04f120ca5de 100644 --- a/i18n/deu/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "debugConfigurationNames": "Konfigurationen, die im Rahmen dieser \"zusammengesetzten\" Konfiguration gestartet werden. Gilt nur, wenn der Typ dieser Konfiguration auf \"zusammengesetzt\" festgelegt ist.", "debugLinuxConfiguration": "Linux-spezifische Startkonfigurationsattribute.", "debugName": "Der Name der Konfiguration. Er wird im Dropdownmenü der Startkonfiguration angezeigt.", "debugOSXConfiguration": "OS X-spezifische Startkonfigurationsattribute.", diff --git a/i18n/deu/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/deu/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 96c3fe30b55..7e22569aeb4 100644 --- a/i18n/deu/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "Empfehlungen sind nur für einen Arbeitsbereichsordner verfügbar.", "OpenExtensionsFile.failed": "Die Datei \"extensions.json\" kann nicht im Ordner \".vscode\" erstellt werden ({0}).", - "OpenGlobalExtensionsStorageFile.failed": "Die Datei \"extensions.json\" kann nicht im Ordner \"{0}\" ({1}) erstellt werden.", + "Uninstalling": "Wird deinstalliert", "builtin": "Integriert", "clearExtensionsInput": "Extensioneingabe löschen", "configureWorkspaceRecommendedExtensions": "Empfohlene Erweiterungen konfigurieren (Arbeitsbereich)", - "deleteSure": "Möchten Sie \"{0}\" deinstallieren?", + "disableAction": "Deaktivieren", + "disableAll": "Alle deaktivieren", + "disableAllWorkspace": "Alle deaktivieren (Arbeitsbereich)", + "disableAlwaysAction.label": "Deaktivieren", + "disableForWorkspaceAction": "Arbeitsbereich", + "disableForWorkspaceAction.label": "Deaktivieren (Arbeitsbereich)", + "disableGloballyAction": "Immer", "enableAction": "Aktivieren", + "enableAll": "Alle aktivieren", + "enableAllWorkspace": "Alle aktivieren (Arbeitsbereich)", + "enableAlwaysAction.label": "Aktivieren", + "enableForWorkspaceAction": "Arbeitsbereich", + "enableForWorkspaceAction.label": "Aktivieren (Arbeitsbereich)", + "enableGloballyAction": "Immer", "installAction": "Installieren", "installExtensions": "Extensions installieren", "installVSIX": "Aus VSIX installieren...", "installing": "Wird installiert.", "openExtensionsFolder": "Extensionordner öffnen", - "postUninstallMessage": "{0} wurde erfolgreich deinstalliert. Führen Sie zur Deaktivierung einen Neustart aus.", - "restart": "Damit diese Extension aktiviert wird, muss dieses Fenster von VS Code neu gestartet werden.\n\nMöchten Sie fortfahren?", - "restartNow": "Jetzt neu starten", + "postDisableMessage": "Möchten Sie dieses Fenster erneut laden, um die Erweiterung \"{0}\" zu deaktivieren?", + "postDisableTooltip": "Zum Deaktivieren erneut laden", + "postEnableMessage": "Möchten Sie dieses Fenster erneut laden, um die Erweiterung \"{0}\" zu aktivieren?", + "postEnableTooltip": "Zum Aktivieren erneut laden", + "postInstallMessage": "Möchten Sie dieses Fenster erneut laden, um die Erweiterung \"{0}\" zu aktivieren?", + "postInstallTooltip": "Zum Aktivieren erneut laden", + "postUninstallMessage": "Möchten Sie dieses Fenster erneut laden, um die Erweiterung \"{0}\" zu deaktivieren?", + "postUninstallTooltip": "Zum Deaktivieren erneut laden", + "reloadAction": "Erneut laden", + "reloadNow": "Jetzt erneut laden", "showDisabledExtensions": "Deaktivierte Erweiterungen anzeigen", "showInstalledExtensions": "Installierte Extensions anzeigen", "showOutdatedExtensions": "Veraltete Extensions anzeigen", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "Empfohlene Extensions anzeigen", "showWorkspaceRecommendedExtensions": "Für den Arbeitsbereich empfohlene Extensions anzeigen", "toggleExtensionsViewlet": "Extensions anzeigen", - "uninstall": "Deinstallieren", + "uninstallAction": "Deinstallieren", "updateAction": "Aktualisieren", "updateAll": "Alle Extensions aktualisieren" } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/deu/src/vs/workbench/parts/git/node/git.lib.i18n.json index ed6cda9de2a..ccf03ee449d 100644 --- a/i18n/deu/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "Datei aus Git kann nicht geöffnet werden.", "fileBinaryError": "Die Datei scheint eine Binärdatei zu sein und kann nicht als Text geöffnet werden." } \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/html/browser/webview.i18n.json b/i18n/deu/src/vs/workbench/parts/html/browser/webview.i18n.json index 8b6ad71cd4e..3c0f0a6b24b 100644 --- a/i18n/deu/src/vs/workbench/parts/html/browser/webview.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/html/browser/webview.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "devtools.webview": "Developer: Webansichtstools" +} \ No newline at end of file diff --git a/i18n/deu/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/deu/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index 07e3a88009f..1f42338b4d1 100644 --- a/i18n/deu/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "Zuerst eine Textdatei öffnen, um zu einer Zeile zu navigieren", "gotoLine": "Gehe zu Zeile...", - "gotoLineColumnLabel": "Gehe zu Zeile {0} und Spalte {1}", + "gotoLineColumnLabel": "Zu Zeile {0} und Zeichen {1} wechseln", "gotoLineHandlerAriaLabel": "Geben Sie eine Zeilennummer ein, zu der navigiert werden soll.", "gotoLineLabel": "Gehe zu Zeile {0}", "gotoLineLabelEmpty": "Zeilennummer eingeben, zu der navigiert werden soll", diff --git a/i18n/deu/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json b/i18n/deu/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json index 6b5146f14a5..d608ec120be 100644 --- a/i18n/deu/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json @@ -8,7 +8,7 @@ "array": "Arrays ({0})", "boolean": "Boolesche Werte ({0})", "cannotRunGotoSymbol": "Zuerst eine Textdatei öffnen, um zu einem Symbol zu navigieren", - "cannotRunGotoSymbolInFile": "Leider liegen keine Symbolinformationen für die Datei vor.", + "cannotRunGotoSymbolInFile": "Keine Symbolinformationen für die Datei vorhanden.", "class": "Klassen ({0})", "entryAriaLabel": "{0}, Symbole", "enum": "Enumerationen ({0})", diff --git a/i18n/deu/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/deu/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 3a32b5d2ad0..4df220eff25 100644 --- a/i18n/deu/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/deu/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "Jetzt herunterladen", + "insiderBuilds": "Tägliche Insider-Builds und Releases!", "later": "Später", + "license": "Lizenz lesen", + "licenseChanged": "Unsere Lizenzbedingungen haben sich geändert. Bitte lesen Sie die neuen Bedingungen.", + "neverShowAgain": "Nicht mehr anzeigen", "noUpdatesAvailable": "Zurzeit sind keine Updates verfügbar.", "read the release notes": "Willkommen bei {0} v{1}! Möchten Sie die Hinweise zu dieser Version lesen?", + "readmore": "Weitere Informationen", "releaseNotes": "Anmerkungen zu dieser Version", "showReleaseNotes": "Anmerkungen zu dieser Version anzeigen", "thereIsUpdateAvailable": "Ein Update ist verfügbar.", diff --git a/i18n/esn/extensions/typescript/out/features/bufferSyncSupport.i18n.json b/i18n/esn/extensions/typescript/out/features/bufferSyncSupport.i18n.json index 80f2e018c49..6bd0c19c5b6 100644 --- a/i18n/esn/extensions/typescript/out/features/bufferSyncSupport.i18n.json +++ b/i18n/esn/extensions/typescript/out/features/bufferSyncSupport.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "close": "Cerrar", + "doNotCheckAgain": "No volver a comprobar", + "moreInformation": "Más información", + "updateTscCheck": "La configuración del usuario de \"typescript.check.tscVersion\" se actualizó a false.", "versionMismatch": "Las versiones no coinciden; global tsc ({0}) != servicio de lenguaje de VS Code ({1}). Pueden producirse errores de compilación incoherente." } \ No newline at end of file diff --git a/i18n/esn/extensions/typescript/package.i18n.json b/i18n/esn/extensions/typescript/package.i18n.json index 40f142f3e7e..e0d0817ec15 100644 --- a/i18n/esn/extensions/typescript/package.i18n.json +++ b/i18n/esn/extensions/typescript/package.i18n.json @@ -4,28 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "configuration.typescript": "TypeScript", - "format.insertSpaceAfterCommaDelimiter": "Define el tratamiento del espacio después de un delimitador de coma", - "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Define el tratamiento del espacio después de la palabra clave function para las funciones anónimas", - "format.insertSpaceAfterKeywordsInControlFlowStatements": "Define el tratamiento del espacio después de las palabras clave en una instrucción de flujo de control", - "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Define el tratamiento del espacio después de la llave de apertura y antes de la llave de cierre de expresiones JSX. Requiere TypeScript >= 2.0.6", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Define el tratamiento del espacio después de los corchetes de apertura y antes de los corchetes de cierre con contenido", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Define el tratamiento del espacio después de los paréntesis de apertura y antes de los paréntesis de cierre con contenido", - "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Define el tratamiento del espacio después de la llave de apertura y antes de la llave de cierre de cadenas de plantilla. Requiere TypeScript >= 2.0.6", - "format.insertSpaceAfterSemicolonInForStatements": " Define el tratamiento del espacio después de punto y coma en una instrucción for", - "format.insertSpaceBeforeAndAfterBinaryOperators": "Define el tratamiento del espacio después de un operador binario", - "format.placeOpenBraceOnNewLineForControlBlocks": "Define si una llave de apertura se incluye en una nueva línea para los bloques de control o no", - "format.placeOpenBraceOnNewLineForFunctions": "Define si una llave de apertura se incluye en una nueva línea para las funciones o no", + "configuration.typescript": "TypeScript.", + "format.insertSpaceAfterCommaDelimiter": "Define el tratamiento del espacio después de un delimitador de coma.", + "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Define el tratamiento del espacio después de la palabra clave function para las funciones anónimas.", + "format.insertSpaceAfterKeywordsInControlFlowStatements": "Define el tratamiento del espacio después de las palabras clave en una instrucción de flujo de control.", + "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Define el tratamiento del espacio después de la llave de apertura y antes de la llave de cierre de las expresiones JSX. Requiere TypeScript >= 2.0.6.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Define el tratamiento del espacio después de los corchetes de apertura y antes de los corchetes de cierre con contenido.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Define el tratamiento del espacio después de los paréntesis de apertura y antes de los paréntesis de cierre con contenido.", + "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Define el tratamiento del espacio después de la llave de apertura y antes de la llave de cierre de cadenas de plantilla. Requiere TypeScript >= 2.0.6.", + "format.insertSpaceAfterSemicolonInForStatements": " Define el tratamiento del espacio después de punto y coma en una instrucción for.", + "format.insertSpaceBeforeAndAfterBinaryOperators": "Define el tratamiento del espacio después de un operador binario.", + "format.placeOpenBraceOnNewLineForControlBlocks": "Define si una llave de apertura se incluye en una nueva línea para los bloques de control o no.", + "format.placeOpenBraceOnNewLineForFunctions": "Define si una llave de apertura se incluye en una nueva línea para las funciones o no.", + "javascript.format.enable": "Habilita o deshabilita el formateador predeterminado de JavaScript.", "javascript.reloadProjects.title": "Recargar proyecto de JavaScript", - "javascript.validate.enable": "Habilitar o deshabilitar la validación de JavaScript", + "javascript.validate.enable": "Habilita o deshabilita la validación de JavaScript.", "typescript.check.tscVersion": "Compruebe si un compilador de TypeScript de instalación global (p. ej., tsc) difiere del servicio de lenguaje de TypeScript usado.", "typescript.check.workspaceVersion": "Compruebe si hay una versión de TypeScript disponible en el área de trabajo.", - "typescript.experimentalAutomaticTypeAcquisition": "Habilita la adquisición de tipos automática. Requiere TypeScript >= 2.0.6 y reiniciar después del cambio.", + "typescript.disableAutomaticTypeAcquisition": "Deshabilita la adquisición automática de tipos. Requiere TypeScript >= 2.0.6 y es necesario reiniciar después de cambiarlo.", + "typescript.format.enable": "Habilita o deshabilita el formateador predeterminado de TypeScript.", "typescript.reloadProjects.title": "Recargar proyecto de TypeScript", "typescript.tsdk.desc": "Especifica la ruta de acceso de carpeta que contiene los archivos lib*.d.ts y tsserver que se van a usar.", "typescript.tsdk_version.desc": "Especifica la versión de tsserver. Solo es necesario si tsserver no se ha instalado con npm.", "typescript.tsserver.experimentalAutoBuild": "Permite la generación automática experimental. Requiere la versión de desarrollo 1.9 o tsserver 2.x y un reinicio de VS Code después de modificarlo.", "typescript.tsserver.trace": "Habilita el seguimiento de los mensajes enviados al servidor de TS.", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Complete las funciones con la signatura de parámetro.", - "typescript.validate.enable": "Habilitar o deshabilitar la validación de TypeScript" + "typescript.validate.enable": "Habilita o deshabilita la validación de TypeScript." } \ No newline at end of file diff --git a/i18n/esn/src/vs/code/electron-main/menus.i18n.json b/i18n/esn/src/vs/code/electron-main/menus.i18n.json index 83a0f1f61c7..ee9c4f92434 100644 --- a/i18n/esn/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/esn/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "S&&alir", "miFind": "&&Buscar", "miFindInFiles": "Buscar &&en archivos", - "miFocusFirstGroup": "&&Grupo izquierdo", - "miFocusSecondGroup": "&&Grupo central", - "miFocusThirdGroup": "&&Grupo derecho", + "miFocusFirstGroup": "&&Primer grupo", + "miFocusSecondGroup": "&&Segundo grupo", + "miFocusThirdGroup": "&&Tercer grupo", "miForward": "&&Reenviar", "miGotoDefinition": "Ir a &&definición", "miGotoFile": "Ir a &&archivo...", "miGotoLine": "Ir a lí&&nea...", "miGotoSymbolInFile": "Ir al &&símbolo en el archivo...", "miGotoSymbolInWorkspace": "Ir al símbolo en el área de &&trabajo...", + "miHideStatusbar": "&&Ocultar barra de estado", "miInstallingUpdate": "Instalando actualización...", - "miLicense": "&&Ver licencia", + "miIntroductoryVideos": "&&Vídeos de introducción", + "miKeyboardShortcuts": "&&Referencia de métodos abreviados de teclado", + "miLicense": "Ver &&licencia", "miMarker": "&&Problemas", - "miMoveSidebar": "&&Mover barra lateral", + "miMoveSidebarLeft": "&&Mover barra lateral a la izquierda", + "miMoveSidebarRight": "&&Mover barra lateral a la derecha", "miNewFile": "&&Nuevo archivo", "miNewWindow": "&&Nueva ventana", "miNextEditor": "&&Editor siguiente", @@ -84,11 +88,13 @@ "miSelectAll": "&&Seleccionar todo", "miSelectColorTheme": "&&Tema de color", "miSelectIconTheme": "Tema de &&iconos de archivo", + "miShowStatusbar": "&&Mostrar barra de estado", "miSplitEditor": "Dividir &&editor", "miSwitchEditor": "Cambiar &&editor", "miSwitchGroup": "Cambiar &&grupo", "miToggleDebugConsole": "Consola de de&&puración", "miToggleDevTools": "&&Alternar herramientas de desarrollo", + "miToggleEditorLayout": "Alternar diseño del grupo de &&editores", "miToggleFullScreen": "Alternar &&pantalla completa", "miToggleIntegratedTerminal": "&&Terminal integrado", "miToggleMenuBar": "Alternar &&barra de menús", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "Alternar caracteres de control &&", "miToggleRenderWhitespace": "Alternar &&representación de espacio en blanco", "miToggleSidebar": "&&Alternar barra lateral", - "miToggleStatusbar": "&&Alternar barra de estado", "miToggleWordWrap": "Alternar &&ajuste automático de línea", "miTwitter": "&&Síganos en Twitter", "miUndo": "&&Deshacer", diff --git a/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json index bf1caf0dce2..57ec19330e5 100644 --- a/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/esn/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "Controla el estilo del cursor. Los valores aceptados son \"block\", \"line\" y \"underline\".", "detectIndentation": "Al abrir un archivo, se detectarán `editor.tabSize` y `editor.insertSpaces` en función del contenido del archivo.", "editorConfigurationTitle": "Editor", + "emptySelectionClipboard": "Controla si al copiar sin selección se copia la línea actual.", "folding": "Controla si el editor tiene habilitado el plegado de código.", "fontFamily": "Controla la familia de fuentes.", "fontLigatures": "Habilita las ligaduras tipográficas.", @@ -23,7 +24,7 @@ "insertSpaces": "Insertar espacios al presionar TAB. Este valor se invalida en función del contenido del archivo cuando `editor.detectIndentation` está activado.", "insertSpaces.errorMessage": "Se esperaba \"boolean\". Tenga en cuenta que el ajuste \"editor.detectIndentation\" ha reemplazado al valor \"auto\".", "lineHeight": "Controla la altura de línea. Utilice 0 para calcular el valor de lineHeight a partir de fontSize.", - "lineNumbers": "Controla la visibilidad de los números de línea", + "lineNumbers": "Controla la presentación de los números de línea. Los valores posibles son \"on\", \"off\" y \"relative\". \"relative\" muestra el número de líneas desde la posición actual del cursor.", "mouseWheelScrollSensitivity": "Se utilizará un multiplicador en los eventos de desplazamiento de la rueda del mouse `deltaX` y `deltaY`", "mouseWheelZoom": "Ampliar la fuente del editor cuando se use la rueda del mouse mientras se presiona Ctrl", "overviewRulerLanes": "Controla el número de decoraciones que pueden aparecer en la misma posición en la regla de visión general", diff --git a/i18n/esn/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/esn/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index a3dad1faf6c..5f04fd6c9e0 100644 --- a/i18n/esn/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "Mostrar ayuda de accesibilidad", - "introMsg": "Gracias por probar las opciones de accesibilidad experimentales de VS Code.", + "introMsg": "Gracias por probar las opciones de accesibilidad de VS Code.", "outroMsg": "Para descartar esta información sobre herramientas y volver al editor, presione Esc.", "status": "Estado:", - "tabFocusModeOffMsg": "Al presionar TAB en este editor, se insertará el carácter de tabulación. Presione {0} para activar o desactivar este comportamiento.", - "tabFocusModeOffMsgNoKb": "Al presionar TAB en este editor, el foco se mueve al siguiente elemento activable. El comando {0} no se puede desencadenar actualmente mediante un enlace de teclado.", - "tabFocusModeOnMsg": "Al presionar TAB en este editor, el foco se mueve al siguiente elemento activable. Presione {0} para activar o desactivar este comportamiento.", - "tabFocusModeOnMsgNoKb": "Al presionar TAB en este editor, el foco se mueve al siguiente elemento activable. El comando {0} no se puede desencadenar actualmente mediante un enlace de teclado." + "tabFocusModeOffMsg": "Al presionar TAB en el editor actual, se insertará el carácter de tabulación. Presione {0} para activar o desactivar este comportamiento.", + "tabFocusModeOffMsgNoKb": "Al presionar TAB en el editor actual, se insertará el carácter de tabulación. El comando {0} no se puede desencadenar actualmente mediante un enlace de teclado.", + "tabFocusModeOnMsg": "Al presionar TAB en el editor actual, el foco se mueve al siguiente elemento activable. Presione {0} para activar o desactivar este comportamiento.", + "tabFocusModeOnMsgNoKb": "Al presionar TAB en el editor actual, el foco se mueve al siguiente elemento activable. El comando {0} no se puede desencadenar actualmente mediante un enlace de teclado." } \ No newline at end of file diff --git a/i18n/esn/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/esn/src/vs/editor/contrib/format/common/formatActions.i18n.json index 172a9250865..3f02c2aff90 100644 --- a/i18n/esn/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/esn/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "Formatear código" + "formatDocument.label": "Dar formato al documento", + "formatSelection.label": "Dar formato a la selección" } \ No newline at end of file diff --git a/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 407fbc13f91..712af3e0d4d 100644 --- a/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/esn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "Cancelar", "doNotInstall": "No", "install": "Sí", "installDependeciesConfirmation": "Al instalar '{0}', se instalan también sus dependencias. ¿Quiere continuar?", @@ -11,6 +12,14 @@ "invalidName": "Extensión no válida: el nombre del manifiesto no coincide.", "invalidPublisher": "Extensión no válida: el publicador del manifiesto no coincide.", "invalidVersion": "Extensión no válida: la versión del manifiesto no coincide.", + "multipleDependentsError": "No se puede desinstalar la extensión '{0}'. Las extensiones '{1}' y '{2}', entre otras, dependen de esta.", "notExists": "No se encontró la extensión.", - "restartCode": "Reinicie Code antes de volver a instalar {0}." + "ok": "Aceptar", + "restartCode": "Reinicie Code antes de volver a instalar {0}.", + "singleDependentError": "No se puede desinstalar la extensión '{0}'. La extensión '{1}' depende de esta.", + "twoDependentsError": "No se puede desinstalar la extensión '{0}'. Las extensiones '{1}' y '{2}' dependen de esta.", + "uninstallAll": "Todo", + "uninstallConfirmation": "¿Seguro que quiere desinstalar '{0}'?", + "uninstallDependeciesConfirmation": "¿Quiere desinstalar solo '{0}' o también sus dependencias?", + "uninstallOnly": "Solo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/esn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index a8ab0dc3ecc..54080785e42 100644 --- a/i18n/esn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/esn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "la propiedad `{0}` se puede omitir o debe ser de tipo \"string[]\"", - "extensionDescription.activationEvents2": "las propiedades `{0}` y `{1}` deben especificarse u omitirse conjuntamente", - "extensionDescription.empty": "Se obtuvo una descripción vacía de la extensión.", - "extensionDescription.engines": "la propiedad `{0}` es obligatoria y debe ser de tipo \"object\"", - "extensionDescription.engines.vscode": "la propiedad `{0}` es obligatoria y debe ser de tipo \"string\"", - "extensionDescription.extensionDependencies": "la propiedad `{0}` se puede omitir o debe ser de tipo \"string[]\"", - "extensionDescription.main1": "la propiedad `{0}` se puede omitir o debe ser de tipo \"string\"", - "extensionDescription.main2": "Se esperaba que \"main\" ({0}) se hubiera incluido en la carpeta de la extensión ({1}). Esto puede hacer que la extensión no sea portátil.", - "extensionDescription.main3": "las propiedades `{0}` y `{1}` deben especificarse u omitirse conjuntamente", - "extensionDescription.name": "la propiedad `{0}` es obligatoria y debe ser de tipo \"string\"", - "extensionDescription.publisher": "la propiedad `{0}` es obligatoria y debe ser de tipo \"string\"", - "extensionDescription.version": "la propiedad `{0}` es obligatoria y debe ser de tipo \"string\"", "vscode.extension.activationEvents": "Eventos de activación de la extensión VS Code.", "vscode.extension.badges": "Matriz de distintivos que se muestran en la barra lateral de la página de extensiones de Marketplace.", "vscode.extension.badges.description": "Descripción del distintivo.", @@ -24,6 +12,7 @@ "vscode.extension.categories": "Categorías que usa la galería de VS Code para clasificar la extensión.", "vscode.extension.contributes": "Todas las contribuciones de la extensión VS Code representadas por este paquete.", "vscode.extension.displayName": "Nombre para mostrar de la extensión que se usa en la galería de VS Code.", + "vscode.extension.engines.vscode": "Para las extensiones de VS Code, especifica la versión de VS Code con la que la extensión es compatible. No puede ser *. Por ejemplo: ^0.10.5 indica compatibilidad con una versión de VS Code mínima de 0.10.5.", "vscode.extension.extensionDependencies": "Dependencias a otras extensiones. El identificador de una extensión siempre es ${publisher}.${name}. Por ejemplo: vscode.csharp.", "vscode.extension.galleryBanner": "Banner usado en VS Code Marketplace.", "vscode.extension.galleryBanner.color": "Color del banner en el encabezado de página de VS Code Marketplace.", diff --git a/i18n/esn/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/esn/src/vs/workbench/browser/actions/openSettings.i18n.json index d7bc1bc47ef..2a51d119e32 100644 --- a/i18n/esn/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "Métodos abreviados de teclado predeterminados", "defaultKeybindingsHeader": "Coloque los enlaces de teclado en el archivo de enlaces de teclado para sobrescribirlos.", "defaultName": "Configuración predeterminada", + "defaultSettingsEditor": "Editor de configuración predeterminada", "defaultSettingsHeader": "Coloque la configuración en el archivo de configuración para sobrescribirla.", "defaultSettingsHeader2": "Consulte http://go.microsoft.com/fwlink/?LinkId=808995 para obtener la configuración de uso más frecuente.", "emptyKeybindingsHeader": "Coloque sus enlaces de teclado en este archivo para sobrescribir los valores predeterminados.", diff --git a/i18n/esn/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/esn/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..37ebb023067 100644 --- a/i18n/esn/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "Diseño horizontal del grupo de editores", + "toggleEditorGroupLayout": "Alternar diseño vertical/horizontal del grupo de editores", + "verticalLayout": "Diseño vertical del grupo de editores", + "view": "Ver" +} \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index e87c992c791..1220c8fe1fb 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "Mostrar todos los editores abiertos", "binaryDiffEditor": "Editor de diferencias binario", - "centerEditorGroupPicker": "Mostrar los editores del grupo central", - "leftEditorGroupPicker": "Mostrar editores del grupo izquierdo", - "rightEditorGroupPicker": "Mostrar editores del grupo derecho", + "groupOnePicker": "Mostrar editores del primer grupo", + "groupThreePicker": "Mostrar editores del tercer grupo", + "groupTwoPicker": "Mostrar editores del segundo grupo", "textDiffEditor": "Editor de diferencias de texto", "textEditor": "Editor de texto", "view": "Ver" diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index ccb6b31cf54..3bde62268df 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "Cerrar otros editores", "evenEditorGroups": "Uniformar anchos del grupo de editores", "focusActiveEditorGroup": "Enfocar grupo de editores activo", - "focusFirstEditorGroup": "Enfocar grupo de editores a la izquierda", + "focusFirstEditorGroup": "Enfocar primer grupo de editores", "focusLastEditorInStack": "Abrir el último editor del grupo", "focusNextGroup": "Enfocar el grupo siguiente", "focusPreviousGroup": "Enfocar el grupo anterior", - "focusSecondEditorGroup": "Enfocar el grupo de editores del centro", - "focusThirdEditorGroup": "Enfocar el grupo de editores a la derecha", + "focusSecondEditorGroup": "Enfocar segundo grupo de editores", + "focusThirdEditorGroup": "Enfocar tercer grupo de editores", "keepEditor": "Mantener editor", "maximizeEditor": "Maximizar el grupo de editores y ocultar la barra lateral", "minimizeOtherEditorGroups": "Minimizar otros grupos de editores", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "Mover el grupo de editores a la derecha", "moveEditorLeft": "Mover el editor a la izquierda", "moveEditorRight": "Mover el editor a la derecha", - "moveEditorToLeftGroup": "Mover el editor al grupo de la izquierda", - "moveEditorToRightGroup": "Mover el editor al grupo de la derecha", + "moveEditorToNextGroup": "Mover editor al grupo siguiente", + "moveEditorToPreviousGroup": "Mover editor al grupo anterior", "navigateEditorGroups": "Navegar entre los grupos de editores", "navigateEditorHistoryByInput": "Abrir el editor anterior desde el historial", "navigateNext": "Hacia delante", @@ -38,12 +38,11 @@ "openPreviousEditor": "Abrir el editor anterior", "openPreviousEditorInGroup": "Abrir el editor recientemente usado anterior en el grupo", "openToSide": "Abrir en el lateral", - "removeFromEditorHistory": "Quitar del historial de editores", "reopenClosedEditor": "Volver a abrir el editor cerrado", "showAllEditors": "Mostrar todos los editores", - "showEditorsInCenterGroup": "Mostrar los editores del grupo central", + "showEditorsInFirstGroup": "Mostrar editores del primer grupo", "showEditorsInGroup": "Mostrar los editores del grupo", - "showEditorsInLeftGroup": "Mostrar los editores del grupo izquierdo", - "showEditorsInRightGroup": "Mostrar los editores del grupo derecho", + "showEditorsInSecondGroup": "Mostrar editores del segundo grupo", + "showEditorsInThirdGroup": "Mostrar editores del tercer grupo", "splitEditor": "Dividir editor" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index 1949a616496..02823fed1c5 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "Centro", "editorOpenError": "No se puede abrir '{0}': {1}.", - "leftGroup": "Izquierda", - "rightGroup": "Derecha" + "groupOneHorizontal": "Superior", + "groupOneVertical": "Izquierda", + "groupThreeHorizontal": "Inferior", + "groupThreeVertical": "Derecha", + "groupTwoHorizontal": "Centro", + "groupTwoVertical": "Centro" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index f89ccb84a68..e1e9f3a68d6 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0}, selector del grupo de editores", "groupLabel": "Grupo: {0}", - "noOpenedEditors": "La lista de editores abiertos actualmente está vacía", + "noOpenedEditors": "La lista de editores abiertos está vacía actualmente en el grupo.", + "noOpenedEditorsAllGroups": "La lista de editores abiertos está vacía actualmente.", "noResultsFound": "No se encontró un editor abierto coincidente", "noResultsFoundInGroup": "No se encontró un editor abierto coincidente en el grupo" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/esn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 8f021d8891c..9d15a9d6dac 100644 --- a/i18n/esn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/esn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "Seleccionar secuencia de fin de línea", "selectEncoding": "Seleccionar Encoding", "selectLanguageMode": "Seleccionar modo de lenguaje", + "showLanguageExtensions": "Buscar extensiones de Marketplace para '{0}'...", "singleSelection": "Lín. {0}, Col. {1}", "singleSelectionRange": "Lín. {0}, Col. {1} ({2} seleccionada)", "spacesSize": "Espacios: {0}", diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index 7434f0fa825..49e77ad94d1 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "El programa solo se detendrá aquí si esta condición es true. Presione ENTRAR para aceptar o Esc para cancelar.", - "breakpointWidgetExpressionPlaceholder": "Interrumpir cuando la expresión se evalúe como true", + "breakpointWidgetExpressionPlaceholder": "Interrumpir cuando la expresión se evalúa como true. Presione \"ENTRAR\" para aceptar o \"Esc\" para cancelar.", "breakpointWidgetHitCountAriaLabel": "El programa solo se detendrá aquí si se alcanza el número de llamadas. Presione ENTRAR para aceptar o Esc para cancelar.", - "breakpointWidgetHitCountPlaceholder": "Interrumpir cuando se alcance el número de llamadas", + "breakpointWidgetHitCountPlaceholder": "Interrumpir cuando se alcance el número de llamadas. Presione \"ENTRAR\" para aceptar o \"Esc\" para cancelar.", "expression": "Expresión", "hitCount": "Número de llamadas" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index 3de6b1ab2c9..63dfd895c6d 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "Depuración: agregar punto de interrupción condicional...", "continueDebug": "Continuar", "deactivateBreakpoints": "Desactivar puntos de interrupción", - "debugActionLabelAndKeybinding": "{0} ({1})", "debugAddToWatch": "Depuración: Agregar a inspección", "debugConsoleAction": "Consola de depuración", "debugEvaluate": "Depuración: Evaluar", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "Deshabilitar todos los puntos de interrupción", "disconnectDebug": "Desconectar", "editConditionalBreakpoint": "Editar punto de interrupción...", + "editWatchExpression": "Editar expresión", "enableAllBreakpoints": "Habilitar todos los puntos de interrupción", "launchJsonNeedsConfigurtion": "Configurar o reparar 'launch.json'", "openLaunchJson": "Abrir {0}", @@ -32,7 +32,6 @@ "removeBreakpoint": "Quitar punto de interrupción", "removeWatchExpression": "Quitar expresión", "renameFunctionBreakpoint": "Cambiar nombre de punto de interrupción de función", - "renameWatchExpression": "Cambiar nombre de expresión", "restartDebug": "Reiniciar", "restartFrame": "Reiniciar marco", "runToCursor": "Depuración: Ejecutar hasta el cursor", diff --git a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index 8416e40b8e2..0a05aa796f7 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "Permite establecer puntos de interrupción para todos los archivos, independientemente de la extensión.", + "allowBreakpointsEverywhere": "Permite establecer un punto de interrupción en cualquier archivo.", "debug": "Depurar", "debugCategory": "Depurar", "debugConfigurationTitle": "Depurar", "debugErrorEditor": "Depurar error", "debugPanel": "Consola de depuración", - "launchConfigDoesNotExist": "La configuración de inicio '{0}' no existe.", - "openExplorerOnEnd": "Abrir automáticamente el viewlet del explorador al final de la sesión de depuración.", + "openExplorerOnEnd": "Abre automáticamente el viewlet del explorador al final de la sesión de depuración.", "toggleDebugPanel": "Consola de depuración", "toggleDebugViewlet": "Mostrar depuración", "view": "Ver" diff --git a/i18n/esn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/esn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 4df0fa4057d..914679b06cb 100644 --- a/i18n/esn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "debugConfigurationNames": "Configuraciones que se iniciarán como parte de esta configuración \"compuesta\". Solo se respeta si el tipo de configuración es \"compuesta\".", "debugLinuxConfiguration": "Atributos de configuración de inicio específicos de Linux.", "debugName": "Nombre de la configuración. Aparece en el menú desplegable de la configuración de inicio.", "debugOSXConfiguration": "Atributos de configuración de inicio específicos de OS X.", diff --git a/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 08e1cf53aab..f8638e5be73 100644 --- a/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "Las recomendaciones solo están disponibles en una carpeta de área de trabajo.", "OpenExtensionsFile.failed": "No se puede crear el archivo \"extensions.json\" dentro de la carpeta \".vscode\" ({0}).", - "OpenGlobalExtensionsStorageFile.failed": "No se puede crear el archivo \"extensions.json\" en la carpeta '{0}' ({1}).", + "Uninstalling": "Desinstalando", "builtin": "Integrada", "clearExtensionsInput": "Borrar entrada de extensiones", "configureWorkspaceRecommendedExtensions": "Configurar extensiones recomendadas (área de trabajo)", - "deleteSure": "¿Seguro que quiere desinstalar '{0}'?", + "disableAction": "Deshabilitar", + "disableAll": "Deshabilitar todo", + "disableAllWorkspace": "Deshabilitar todo (área de trabajo)", + "disableAlwaysAction.label": "Deshabilitar", + "disableForWorkspaceAction": "Área de trabajo", + "disableForWorkspaceAction.label": "Deshabilitar (área de trabajo)", + "disableGloballyAction": "Siempre", "enableAction": "Habilitar", + "enableAll": "Habilitar todo", + "enableAllWorkspace": "Habilitar todo (área de trabajo)", + "enableAlwaysAction.label": "Habilitar", + "enableForWorkspaceAction": "Área de trabajo", + "enableForWorkspaceAction.label": "Habilitar (área de trabajo)", + "enableGloballyAction": "Siempre", "installAction": "Instalar", "installExtensions": "Instalar extensiones", "installVSIX": "Instalar desde VSIX...", "installing": "Instalando", "openExtensionsFolder": "Abrir carpeta de extensiones", - "postUninstallMessage": "{0} se desinstaló correctamente. Reinicie para desactivarlo.", - "restart": "Para habilitar esta extensión, esta ventana de VS Code se debe reiniciar.\n\n¿Desea continuar?", - "restartNow": "Reiniciar ahora", + "postDisableMessage": "¿Quiere recargar esta ventana para deshabilitar la extensión '{0}'?", + "postDisableTooltip": "Recargar para deshabilitar", + "postEnableMessage": "¿Quiere recargar esta ventana para habilitar la extensión '{0}'?", + "postEnableTooltip": "Recargar para habilitar", + "postInstallMessage": "¿Quiere recargar esta ventana para activar la extensión '{0}'?", + "postInstallTooltip": "Recargar para activar", + "postUninstallMessage": "¿Quiere recargar esta ventana para desactivar la extensión '{0}'?", + "postUninstallTooltip": "Recargar para desactivar", + "reloadAction": "Recargar", + "reloadNow": "Recargar ahora", "showDisabledExtensions": "Mostrar extensiones deshabilitadas", "showInstalledExtensions": "Mostrar extensiones instaladas", "showOutdatedExtensions": "Mostrar extensiones obsoletas", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "Mostrar extensiones recomendadas", "showWorkspaceRecommendedExtensions": "Mostrar extensiones recomendadas del área de trabajo", "toggleExtensionsViewlet": "Mostrar extensiones", - "uninstall": "Desinstalar", + "uninstallAction": "Desinstalar", "updateAction": "Actualizar", "updateAll": "Actualizar todas las extensiones" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/esn/src/vs/workbench/parts/git/node/git.lib.i18n.json index 1d8632efe35..0076485355d 100644 --- a/i18n/esn/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "No se puede abrir el archivo de GIT.", "fileBinaryError": "El archivo parece ser binario y no se puede abrir como texto" } \ No newline at end of file diff --git a/i18n/esn/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/esn/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index e4e2ffb763b..2580dad4b88 100644 --- a/i18n/esn/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "Abrir un archivo de texto antes de ir a una línea", "gotoLine": "Ir a la línea...", - "gotoLineColumnLabel": "Ir a la línea {0} y la columna {1}", + "gotoLineColumnLabel": "Ir a la línea {0} y al carácter {1}", "gotoLineHandlerAriaLabel": "Escriba el número de la línea a la que quiere navegar.", "gotoLineLabel": "Ir a la línea {0}", "gotoLineLabelEmpty": "Escriba el número de línea a la cual quiera navegar.", diff --git a/i18n/esn/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json b/i18n/esn/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json index 0684f163ee2..ff9126d326d 100644 --- a/i18n/esn/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json @@ -8,7 +8,7 @@ "array": "matrices ({0})", "boolean": "booleanos ({0})", "cannotRunGotoSymbol": "Abrir un archivo de texto antes de ir a un símbolo", - "cannotRunGotoSymbolInFile": "Lamentablemente, no tenemos información de símbolos para el archivo", + "cannotRunGotoSymbolInFile": "No hay información de símbolos para el archivo.", "class": "clases ({0})", "entryAriaLabel": "{0}, símbolos", "enum": "enumeraciones ({0})", diff --git a/i18n/esn/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/esn/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 9ecf305e3c5..a0a1af41358 100644 --- a/i18n/esn/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/esn/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "Descargar ahora", + "insiderBuilds": "Compilaciones y versiones de Insider todos los días.", "later": "Más tarde", + "license": "Leer licencia", + "licenseChanged": "Los términos de licencia han cambiado, revíselos.", + "neverShowAgain": "No volver a mostrar", "noUpdatesAvailable": "Actualmente no hay actualizaciones disponibles.", "read the release notes": "{0} v{1}. ¿Quiere leer las notas de la versión?", + "readmore": "Leer más", "releaseNotes": "Notas de la versión", "showReleaseNotes": "Mostrar las notas de la versión", "thereIsUpdateAvailable": "Hay una actualización disponible.", diff --git a/i18n/fra/extensions/typescript/out/features/bufferSyncSupport.i18n.json b/i18n/fra/extensions/typescript/out/features/bufferSyncSupport.i18n.json index bb0e3ed7d0c..29085f210c1 100644 --- a/i18n/fra/extensions/typescript/out/features/bufferSyncSupport.i18n.json +++ b/i18n/fra/extensions/typescript/out/features/bufferSyncSupport.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "close": "Fermer", + "doNotCheckAgain": "Ne plus vérifier", + "moreInformation": "Informations", + "updateTscCheck": "Mise à jour du paramètre utilisateur 'typescript.check.tscVersion' avec la valeur false", "versionMismatch": "Incompatibilité de version ! global tsc ({0}) != Service de langage de VS Code ({1}). Des erreurs de compilation incohérentes risquent de se produire" } \ No newline at end of file diff --git a/i18n/fra/extensions/typescript/package.i18n.json b/i18n/fra/extensions/typescript/package.i18n.json index 1da479dd9ef..8e0c6424dfb 100644 --- a/i18n/fra/extensions/typescript/package.i18n.json +++ b/i18n/fra/extensions/typescript/package.i18n.json @@ -4,28 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "configuration.typescript": "TypeScript", - "format.insertSpaceAfterCommaDelimiter": "Définit le traitement des espaces après une virgule de délimitation", - "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Définit le traitement des espaces après le mot clé function pour les fonctions anonymes", - "format.insertSpaceAfterKeywordsInControlFlowStatements": "Définit le traitement des espaces après des mots clés dans une instruction de flux de contrôle", - "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Définit la gestion de l'espace après l'ouverture et avant la fermeture des accolades de l'expression JSX. Nécessite TypeScript >= 2.0.6", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Définit le traitement des espaces après l'ouverture et avant la fermeture de crochets non vides", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Définit le traitement des espaces après l'ouverture et avant la fermeture de parenthèses non vides", - "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Définit la gestion de l'espace après l'ouverture et avant la fermeture des accolades de la chaîne de modèle. Nécessite TypeScript >= 2.0.6", - "format.insertSpaceAfterSemicolonInForStatements": " Définit le traitement des espaces après un point-virgule dans une instruction for", - "format.insertSpaceBeforeAndAfterBinaryOperators": "Définit le traitement des espaces après un opérateur binaire", - "format.placeOpenBraceOnNewLineForControlBlocks": "Définit si une accolade ouvrante dans un bloc de contrôle est placée ou non sur une nouvelle ligne", - "format.placeOpenBraceOnNewLineForFunctions": "Définit si une accolade ouvrante dans une fonction est placée ou non sur une nouvelle ligne", + "configuration.typescript": "TypeScript.", + "format.insertSpaceAfterCommaDelimiter": "Définit le traitement des espaces après une virgule de délimitation.", + "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Définit le traitement des espaces après le mot clé function pour les fonctions anonymes.", + "format.insertSpaceAfterKeywordsInControlFlowStatements": "Définit le traitement des espaces après des mots clés dans une instruction de flux de contrôle.", + "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Définit la gestion de l'espace après l'ouverture et avant la fermeture des accolades de l'expression JSX. Nécessite TypeScript >= 2.0.6.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Définit le traitement des espaces après l'ouverture et avant la fermeture de crochets non vides.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Définit le traitement des espaces après l'ouverture et avant la fermeture de parenthèses non vides.", + "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Définit la gestion de l'espace après l'ouverture et avant la fermeture des accolades de la chaîne de modèle. Nécessite TypeScript >= 2.0.6.", + "format.insertSpaceAfterSemicolonInForStatements": " Définit le traitement des espaces après un point-virgule dans une instruction for.", + "format.insertSpaceBeforeAndAfterBinaryOperators": "Définit le traitement des espaces après un opérateur binaire.", + "format.placeOpenBraceOnNewLineForControlBlocks": "Définit si une accolade ouvrante dans un bloc de contrôle est placée ou non sur une nouvelle ligne.", + "format.placeOpenBraceOnNewLineForFunctions": "Définit si une accolade ouvrante dans une fonction est placée ou non sur une nouvelle ligne.", + "javascript.format.enable": "Activez/désactivez le formateur JavaScript par défaut.", "javascript.reloadProjects.title": "Recharger le projet JavaScript", - "javascript.validate.enable": "Activer/désactiver la validation JavaScript", + "javascript.validate.enable": "Activez/désactivez la validation JavaScript.", "typescript.check.tscVersion": "Vérifiez si un compilateur TypeScript installé globalement (par exemple tsc) est différent du service de langage TypeScript.", - "typescript.check.workspaceVersion": "Vérifier si une version de TypeScript est disponible dans l'espace de travail", - "typescript.experimentalAutomaticTypeAcquisition": "Active l'acquisition de type automatique. Nécessite TypeScript >= 2.0.6 et un redémarrage, une fois le changement effectué.", + "typescript.check.workspaceVersion": "Vérifiez si une version de TypeScript est disponible dans l'espace de travail.", + "typescript.disableAutomaticTypeAcquisition": "Désactive l'acquisition de type automatique. Nécessite TypeScript >= 2.0.6 et un redémarrage, une fois le changement effectué.", + "typescript.format.enable": "Activez/désactivez le formateur TypeScript par défaut.", "typescript.reloadProjects.title": "Recharger le projet TypeScript", "typescript.tsdk.desc": "Spécifie le chemin de dossier contenant les fichiers tsserver et lib*.d.ts à utiliser.", "typescript.tsdk_version.desc": "Spécifie la version de tsserver. Uniquement nécessaire si tsserver n'est pas installé via npm.", "typescript.tsserver.experimentalAutoBuild": "Active la build automatique expérimentale. Nécessite la version 1.9 dev ou 2.x tsserver et le redémarrage du code VS une fois celui-ci modifié.", - "typescript.tsserver.trace": "Active le traçage de l'envoi des messages au serveur TS", + "typescript.tsserver.trace": "Active le traçage de l'envoi des messages au serveur TS.", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Fonctions complètes avec leur signature de paramètre.", - "typescript.validate.enable": "Activer/désactiver la validation TypeScript" + "typescript.validate.enable": "Activez/désactivez la validation TypeScript." } \ No newline at end of file diff --git a/i18n/fra/src/vs/code/electron-main/menus.i18n.json b/i18n/fra/src/vs/code/electron-main/menus.i18n.json index a0701ffa7a0..e700f5666de 100644 --- a/i18n/fra/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/fra/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "&&Quitter", "miFind": "&&Rechercher", "miFindInFiles": "Rechercher dans les f&&ichiers", - "miFocusFirstGroup": "Groupe g&&auche", - "miFocusSecondGroup": "&&Centrer le groupe", - "miFocusThirdGroup": "&&Groupe droit", + "miFocusFirstGroup": "&&Premier groupe", + "miFocusSecondGroup": "&&Deuxième groupe", + "miFocusThirdGroup": "&&Troisième groupe", "miForward": "&&Suivant", "miGotoDefinition": "Atteindre la &&définition", "miGotoFile": "Atteindre le &&fichier...", "miGotoLine": "Atteindre la &&ligne...", "miGotoSymbolInFile": "Atteindre le &&symbole dans le fichier...", "miGotoSymbolInWorkspace": "Accéder au symbole dans l'espace de tra&&vail...", + "miHideStatusbar": "&&Masquer la barre d'état", "miInstallingUpdate": "Installation de la mise à jour...", + "miIntroductoryVideos": "&&Vidéos d'introduction", + "miKeyboardShortcuts": "Référence des racco&&urcis clavier", "miLicense": "Affic&&her la licence", "miMarker": "&&Problèmes", - "miMoveSidebar": "Déplacer la &&barre latérale", + "miMoveSidebarLeft": "Déplacer la &&barre latérale vers la gauche", + "miMoveSidebarRight": "Déplacer la &&barre latérale vers la droite", "miNewFile": "&&Nouveau fichier", "miNewWindow": "&&Nouvelle fenêtre", "miNextEditor": "Éditeur &&suivant", @@ -84,11 +88,13 @@ "miSelectAll": "&&Sélectionner tout", "miSelectColorTheme": "Thème de &&couleur", "miSelectIconTheme": "Thème d'&&icône de fichier", + "miShowStatusbar": "Affic&&her la barre d'état", "miSplitEditor": "Fractionner l'édit&&eur", "miSwitchEditor": "Changer d'é&&diteur", "miSwitchGroup": "Changer de gr&&oupe", "miToggleDebugConsole": "Console de dé&&bogage", "miToggleDevTools": "Activer/désactiver les ou&&tils de développement", + "miToggleEditorLayout": "Activer/désactiver la &&disposition du groupe d'éditeurs", "miToggleFullScreen": "Plei&&n écran", "miToggleIntegratedTerminal": "&&Terminal intégré", "miToggleMenuBar": "Activer/désactiver la &&barre de menus", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "Activer/désactiver les &&caractères de contrôle", "miToggleRenderWhitespace": "Activer/désactiver &&Restituer l'espace", "miToggleSidebar": "Activer/désactiver la &&barre latérale", - "miToggleStatusbar": "&&Activer/désactiver la barre d'état", "miToggleWordWrap": "Activer/désactiver le retour automatique à la &&ligne", "miTwitter": "Re&&joignez-nous sur Twitter", "miUndo": "Ann&&uler", diff --git a/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json index b44d227a0e5..faeae842df7 100644 --- a/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/fra/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "Contrôle le style du curseur. Valeurs acceptées : 'block', 'line' et 'underline'", "detectIndentation": "Quand vous ouvrez un fichier, 'editor.tabSize' et 'editor.insertSpaces' sont détectés en fonction du contenu du fichier.", "editorConfigurationTitle": "Éditeur", + "emptySelectionClipboard": "Contrôle si la copie sans sélection permet de copier la ligne actuelle.", "folding": "Contrôle si le pliage de code est activé dans l'éditeur", "fontFamily": "Contrôle la famille de polices.", "fontLigatures": "Active les ligatures de police", @@ -23,7 +24,7 @@ "insertSpaces": "Des espaces sont insérés quand vous appuyez sur la touche Tab. Ce paramètre est remplacé en fonction du contenu du fichier quand 'editor.detectIndentation' est activé.", "insertSpaces.errorMessage": "'boolean' attendu. Notez que la valeur \"auto\" a été remplacée par le paramètre 'editor.detectIndentation'.", "lineHeight": "Contrôle la hauteur de ligne. Utilisez 0 pour calculer lineHeight à partir de fontSize.", - "lineNumbers": "Contrôle la visibilité des numéros de ligne", + "lineNumbers": "Contrôle l'affichage des numéros de ligne. Les valeurs possibles sont 'activé', 'désactivé' et 'relatif'. La valeur 'relatif' indique le numéro de ligne à partir de la position actuelle du curseur.", "mouseWheelScrollSensitivity": "Multiplicateur à utiliser pour le 'deltaX' et le 'deltaY' des événements de défilement de la roulette de la souris", "mouseWheelZoom": "Agrandir ou réduire la police de l'éditeur quand l'utilisateur fait tourner la roulette de la souris tout en maintenant la touche Ctrl enfoncée", "overviewRulerLanes": "Contrôle le nombre d'ornements pouvant s'afficher à la même position dans la règle d'aperçu", diff --git a/i18n/fra/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/fra/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index ad8c8f4d6b2..2cfd9cf22ca 100644 --- a/i18n/fra/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "Afficher l'aide sur l'accessibilité", - "introMsg": "Merci de tester les options d'accessibilité expérimentales de VS Code.", + "introMsg": "Nous vous remercions de tester les options d'accessibilité de VS Code.", "outroMsg": "Vous pouvez masquer cette info-bulle et revenir à l'éditeur en appuyant sur Échap.", "status": "État :", - "tabFocusModeOffMsg": "Appuyez sur Tab dans cet éditeur pour insérer le caractère de tabulation. Activez ou désactivez ce comportement en appuyant sur {0}.", - "tabFocusModeOffMsgNoKb": "Appuyez sur Tab dans cet éditeur pour déplacer le focus vers le prochain élément pouvant être désigné comme élément actif. Actuellement, la commande {0} ne peut pas être déclenchée par une combinaison de touches.", - "tabFocusModeOnMsg": "Appuyez sur Tab dans cet éditeur pour déplacer le focus vers le prochain élément pouvant être désigné comme élément actif. Activez ou désactivez ce comportement en appuyant sur {0}.", - "tabFocusModeOnMsgNoKb": "Appuyez sur Tab dans cet éditeur pour déplacer le focus vers le prochain élément pouvant être désigné comme élément actif. Actuellement, la commande {0} ne peut pas être déclenchée par une combinaison de touches." + "tabFocusModeOffMsg": "Appuyez sur Tab dans l'éditeur pour insérer le caractère de tabulation. Activez ou désactivez ce comportement en appuyant sur {0}.", + "tabFocusModeOffMsgNoKb": "Appuyez sur Tab dans l'éditeur pour insérer le caractère de tabulation. La commande {0} ne peut pas être déclenchée par une combinaison de touches.", + "tabFocusModeOnMsg": "Appuyez sur Tab dans l'éditeur pour déplacer le focus vers le prochain élément pouvant être désigné comme élément actif. Activez ou désactivez ce comportement en appuyant sur {0}.", + "tabFocusModeOnMsgNoKb": "Appuyez sur Tab dans l'éditeur pour déplacer le focus vers le prochain élément pouvant être désigné comme élément actif. La commande {0} ne peut pas être déclenchée par une combinaison de touches." } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/fra/src/vs/editor/contrib/format/common/formatActions.i18n.json index c34faf35bcb..8c44a8881e5 100644 --- a/i18n/fra/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/fra/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "Code de format" + "formatDocument.label": "Mettre en forme le document", + "formatSelection.label": "Mettre en forme la sélection" } \ No newline at end of file diff --git a/i18n/fra/src/vs/editor/node/textMate/TMSyntax.i18n.json b/i18n/fra/src/vs/editor/node/textMate/TMSyntax.i18n.json index 7b645222301..d3707f7650d 100644 --- a/i18n/fra/src/vs/editor/node/textMate/TMSyntax.i18n.json +++ b/i18n/fra/src/vs/editor/node/textMate/TMSyntax.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.embeddedLanguages": "Valeur non valide dans 'contributes.{0}.embeddedLanguages'. Il doit s'agir d'un mappage d'objets entre le nom de portée et le langage. Valeur fournie : {1}", "invalid.injectTo": "Valeur non valide dans 'contributes.{0}.injectTo'. Il doit s'agir d'un tableau de noms de portées de langage. Valeur fournie : {1}", "invalid.language": "Langage inconnu dans 'contributes.{0}.language'. Valeur fournie : {1}", "invalid.path.0": "Chaîne attendue dans 'contributes.{0}.path'. Valeur fournie : {1}", "invalid.path.1": "'contributes.{0}.path' ({1}) est censé être inclus dans le dossier ({2}) de l'extension. Cela risque de rendre l'extension non portable.", "invalid.scopeName": "Chaîne attendue dans 'contributes.{0}.scopeName'. Valeur fournie : {1}", "vscode.extension.contributes.grammars": "Ajoute des générateurs de jetons TextMate.", + "vscode.extension.contributes.grammars.embeddedLanguages": "Mappage du nom de portée à l'ID de langage si cette grammaire contient des langages incorporés.", "vscode.extension.contributes.grammars.injectTo": "Liste de noms des portées de langage auxquelles cette grammaire est injectée.", "vscode.extension.contributes.grammars.language": "Identificateur de langage pour lequel cette syntaxe est ajoutée.", "vscode.extension.contributes.grammars.path": "Chemin du fichier tmLanguage. Le chemin est relatif au dossier d'extensions et commence généralement par './syntaxes/'.", diff --git a/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 98d79943bcb..4f766790ab1 100644 --- a/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/fra/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "Annuler", "doNotInstall": "Non", "install": "Oui", "installDependeciesConfirmation": "L'installation de '{0}' entraîne également l'installation de ses dépendances. Voulez-vous continuer ?", @@ -11,6 +12,14 @@ "invalidName": "Extension non valide : non-correspondance du nom du manifeste.", "invalidPublisher": "Extension non valide : non-correspondance de l'éditeur du manifeste.", "invalidVersion": "Extension non valide : non-correspondance de la version du manifeste.", + "multipleDependentsError": "Impossible de désinstaller l'extension '{0}'. Les extensions '{1}', '{2}' et d'autres extensions en dépendent.", "notExists": "Extension introuvable", - "restartCode": "Redémarrez Code avant de réinstaller {0}." + "ok": "OK", + "restartCode": "Redémarrez Code avant de réinstaller {0}.", + "singleDependentError": "Impossible de désinstaller l'extension '{0}'. L'extension '{1}' en dépend.", + "twoDependentsError": "Impossible de désinstaller l'extension '{0}'. Les extensions '{1}' et '{2}' en dépendent.", + "uninstallAll": "Tout", + "uninstallConfirmation": "Voulez-vous vraiment désinstaller '{0}' ?", + "uninstallDependeciesConfirmation": "Voulez-vous désinstaller uniquement '{0}' ou également ses dépendances ?", + "uninstallOnly": "Uniquement" } \ No newline at end of file diff --git a/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index bcb7190dc73..37401ca0ea8 100644 --- a/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/fra/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "la propriété '{0}' peut être omise ou doit être de type 'string[]'", - "extensionDescription.activationEvents2": "les propriétés '{0}' et '{1}' doivent être toutes les deux spécifiées ou toutes les deux omises", - "extensionDescription.empty": "Description d'extension vide obtenue", - "extensionDescription.engines": "la propriété '{0}' est obligatoire et doit être de type 'object'", - "extensionDescription.engines.vscode": "la propriété '{0}' est obligatoire et doit être de type 'string'", - "extensionDescription.extensionDependencies": "la propriété '{0}' peut être omise ou doit être de type 'string[]'", - "extensionDescription.main1": "La propriété '{0}' peut être omise ou doit être de type 'string'", - "extensionDescription.main2": "'main' ({0}) est censé être inclus dans le dossier ({1}) de l'extension. Cela risque de rendre l'extension non portable.", - "extensionDescription.main3": "les propriétés '{0}' et '{1}' doivent être toutes les deux spécifiées ou toutes les deux omises", - "extensionDescription.name": "la propriété '{0}' est obligatoire et doit être de type 'string'", - "extensionDescription.publisher": "la propriété '{0}' est obligatoire et doit être de type 'string'", - "extensionDescription.version": "la propriété '{0}' est obligatoire et doit être de type 'string'", "vscode.extension.activationEvents": "Événements d'activation pour l'extension VS Code.", "vscode.extension.badges": "Ensemble de badges à afficher dans la barre latérale de la page d'extensions de Marketplace.", "vscode.extension.badges.description": "Description du badge.", @@ -24,6 +12,7 @@ "vscode.extension.categories": "Catégories utilisées par la galerie VS Code pour catégoriser l'extension.", "vscode.extension.contributes": "Toutes les contributions de l'extension VS Code représentées par ce package.", "vscode.extension.displayName": "Nom d'affichage de l'extension utilisée dans la galerie VS Code.", + "vscode.extension.engines.vscode": "Pour les extensions VS Code, spécifie la version de VS Code avec laquelle l'extension est compatible. Ne peut pas être *. Exemple : ^0.10.5 indique une compatibilité avec la version minimale 0.10.5 de VS Code.", "vscode.extension.extensionDependencies": "Dépendances envers d'autres extensions. L'identificateur d'une extension est toujours ${publisher}.${name}. Exemple : vscode.csharp.", "vscode.extension.galleryBanner": "Bannière utilisée dans le marketplace VS Code.", "vscode.extension.galleryBanner.color": "Couleur de la bannière de l'en-tête de page du marketplace VS Code.", diff --git a/i18n/fra/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/fra/src/vs/workbench/browser/actions/openSettings.i18n.json index e5cae20bd65..bf11ad27f62 100644 --- a/i18n/fra/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "Raccourcis clavier par défaut", "defaultKeybindingsHeader": "Remplacez les combinaisons de touches dans votre fichier de combinaisons de touches.", "defaultName": "Paramètres par défaut", + "defaultSettingsEditor": "Éditeur de paramètres par défaut", "defaultSettingsHeader": "Remplacez les paramètres dans votre fichier de paramètres.", "defaultSettingsHeader2": "Pour découvrir les paramètres les plus souvent utilisés, consultez http://go.microsoft.com/fwlink/?LinkId=808995.", "emptyKeybindingsHeader": "Placez vos combinaisons de touches dans ce fichier pour remplacer les valeurs par défaut", diff --git a/i18n/fra/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/fra/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..145c767bc0a 100644 --- a/i18n/fra/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "Disposition horizontale du groupe d'éditeurs", + "toggleEditorGroupLayout": "Activer/désactiver la disposition horizontale/verticale du groupe d'éditeurs", + "verticalLayout": "Disposition verticale du groupe d'éditeurs", + "view": "Affichage" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 2a44a424d1c..68ca5a823c3 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "Afficher tous les éditeurs ouverts", "binaryDiffEditor": "Éditeur de différences binaires", - "centerEditorGroupPicker": "Afficher les éditeurs dans le groupe du milieu", - "leftEditorGroupPicker": "Afficher les éditeurs dans le groupe de gauche", - "rightEditorGroupPicker": "Afficher les éditeurs dans le groupe de droite", + "groupOnePicker": "Afficher les éditeurs du premier groupe", + "groupThreePicker": "Afficher les éditeurs du troisième groupe", + "groupTwoPicker": "Afficher les éditeurs du deuxième groupe", "textDiffEditor": "Éditeur de différences textuelles", "textEditor": "Éditeur de texte", "view": "Affichage" diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 56e09ab573a..f47e4814f7d 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "Fermer les autres éditeurs", "evenEditorGroups": "Même largeur pour le groupe d'éditeurs", "focusActiveEditorGroup": "Placer le focus sur le groupe d'éditeurs d'actifs", - "focusFirstEditorGroup": "Focus sur le groupe d'éditeurs de gauche", + "focusFirstEditorGroup": "Focus sur le premier groupe d'éditeurs", "focusLastEditorInStack": "Ouvrir le dernier éditeur du groupe", "focusNextGroup": "Focus sur le groupe suivant", "focusPreviousGroup": "Focus sur le groupe précédent", - "focusSecondEditorGroup": "Focus sur le groupe d'éditeurs du centre", - "focusThirdEditorGroup": "Focus sur le groupe d'éditeurs de droite", + "focusSecondEditorGroup": "Focus sur le deuxième groupe d'éditeurs", + "focusThirdEditorGroup": "Focus sur le troisième groupe d'éditeurs", "keepEditor": "Conserver l'éditeur", "maximizeEditor": "Agrandir le groupe d'éditeurs et masquer la barre latérale", "minimizeOtherEditorGroups": "Réduire les autres groupes d'éditeurs", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "Déplacer le groupe d'éditeurs vers la droite", "moveEditorLeft": "Déplacer l'éditeur vers la gauche", "moveEditorRight": "Déplacer l'éditeur vers la droite", - "moveEditorToLeftGroup": "Déplacer l'éditeur dans le groupe vers la gauche", - "moveEditorToRightGroup": "Déplacer l'éditeur dans le groupe vers la droite", + "moveEditorToNextGroup": "Déplacer l'éditeur vers le groupe suivant", + "moveEditorToPreviousGroup": "Déplacer l'éditeur vers le groupe précédent", "navigateEditorGroups": "Naviguer entre les groupes d'éditeurs", "navigateEditorHistoryByInput": "Ouvrir l'éditeur précédent dans l'historique", "navigateNext": "Suivant", @@ -38,12 +38,11 @@ "openPreviousEditor": "Ouvrir l'éditeur précédent", "openPreviousEditorInGroup": "Ouvrir l'éditeur précédent du groupe", "openToSide": "Ouvrir sur le côté", - "removeFromEditorHistory": "Supprimer de l'historique des éditeurs", "reopenClosedEditor": "Rouvrir l'éditeur fermé", "showAllEditors": "Afficher tous les éditeurs", - "showEditorsInCenterGroup": "Afficher les éditeurs dans le groupe du milieu", + "showEditorsInFirstGroup": "Afficher les éditeurs du premier groupe", "showEditorsInGroup": "Afficher les éditeurs du groupe", - "showEditorsInLeftGroup": "Afficher les éditeurs dans le groupe de gauche", - "showEditorsInRightGroup": "Afficher les éditeurs dans le groupe de droite", + "showEditorsInSecondGroup": "Afficher les éditeurs du deuxième groupe", + "showEditorsInThirdGroup": "Afficher les éditeurs du troisième groupe", "splitEditor": "Fractionner l'éditeur" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index fdff11237d2..e11e9e79ca4 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "Centre", "editorOpenError": "Impossible d'ouvrir '{0}' : {1}.", - "leftGroup": "Gauche", - "rightGroup": "Droite" + "groupOneHorizontal": "Haut", + "groupOneVertical": "Gauche", + "groupThreeHorizontal": "Bas", + "groupThreeVertical": "Droite", + "groupTwoHorizontal": "Centre", + "groupTwoVertical": "Centre" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index b5611dace45..0eeab950342 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0}, sélecteur de groupes d'éditeurs", "groupLabel": "Groupe : {0}", - "noOpenedEditors": "La liste des éditeurs ouverts est vide", + "noOpenedEditors": "La liste des éditeurs ouverts dans le groupe est vide", + "noOpenedEditorsAllGroups": "La liste des éditeurs ouverts est vide", "noResultsFound": "Éditeur ouvert correspondant introuvable", "noResultsFoundInGroup": "Éditeur ouvert correspondant introuvable dans le groupe" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/fra/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 5187382c079..0d77fdff8ee 100644 --- a/i18n/fra/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/fra/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "Sélectionner la séquence de fin de ligne", "selectEncoding": "Sélectionner l'encodage", "selectLanguageMode": "Sélectionner le mode de langage", + "showLanguageExtensions": "Rechercher '{0}' dans les extensions Marketplace...", "singleSelection": "Li {0}, Col {1}", "singleSelectionRange": "Li {0}, Col {1} ({2} sélectionné)", "spacesSize": "Espaces : {0}", diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index de655df163f..f8425f023f9 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "Le programme s'arrête ici uniquement si cette condition a la valeur true. Appuyez sur Entrée pour accepter, ou sur Échap pour annuler.", - "breakpointWidgetExpressionPlaceholder": "Arrêter quand l'expression prend la valeur true", + "breakpointWidgetExpressionPlaceholder": "Arrêt quand l'expression prend la valeur true. 'Entrée' pour accepter ou 'Échap' pour annuler.", "breakpointWidgetHitCountAriaLabel": "Le programme s'arrête ici uniquement si le nombre d'accès est atteint. Appuyez sur Entrée pour accepter, ou sur Échap pour annuler.", - "breakpointWidgetHitCountPlaceholder": "Arrêter quand le nombre d'accès est atteint", + "breakpointWidgetHitCountPlaceholder": "Arrêt quand le nombre d'accès est atteint. 'Entrée' pour accepter ou 'Échap' pour annuler.", "expression": "Expression", "hitCount": "Nombre d'accès" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index f1609d2a6d4..6717d5fb913 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "Déboguer : ajouter un point d'arrêt conditionnel...", "continueDebug": "Continuer", "deactivateBreakpoints": "Désactiver les points d'arrêt", - "debugActionLabelAndKeybinding": "{0} ({1})", "debugAddToWatch": "Déboguer : ajouter à la fenêtre Espion", "debugConsoleAction": "Console de débogage", "debugEvaluate": "Déboguer : évaluer", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "Désactiver tous les points d'arrêt", "disconnectDebug": "Déconnecter", "editConditionalBreakpoint": "Modifier un point d'arrêt...", + "editWatchExpression": "Modifier l'expression", "enableAllBreakpoints": "Activer tous les points d'arrêt", "launchJsonNeedsConfigurtion": "Configurer ou corriger 'launch.json'", "openLaunchJson": "Ouvrir {0}", @@ -32,7 +32,6 @@ "removeBreakpoint": "Supprimer un point d'arrêt", "removeWatchExpression": "Supprimer une expression", "renameFunctionBreakpoint": "Renommer un point d'arrêt sur fonction", - "renameWatchExpression": "Renommer une expression", "restartDebug": "Redémarrer", "restartFrame": "Redémarrer le frame", "runToCursor": "Déboguer : exécuter jusqu'au curseur", diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index 9f682d4f781..134055b4275 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "Autorise la définition de points d'arrêt pour tous les fichiers, quelle que soit l'extension.", + "allowBreakpointsEverywhere": "Permet de définir un point d'arrêt dans un fichier", "debug": "Déboguer", "debugCategory": "Déboguer", "debugConfigurationTitle": "Déboguer", "debugErrorEditor": "Erreur de débogage", "debugPanel": "Console de débogage", - "launchConfigDoesNotExist": "La configuration de lancement '{0}' n'existe pas.", - "openExplorerOnEnd": "Ouvre automatiquement la viewlet d'exploration à la fin d'une session de débogage.", + "openExplorerOnEnd": "Ouvrir automatiquement la viewlet d'exploration à la fin d'une session de débogage", "toggleDebugPanel": "Console de débogage", "toggleDebugViewlet": "Afficher le débogage", "view": "Affichage" diff --git a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json index bb9c7c9b52a..5dafff9aa55 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json @@ -12,6 +12,7 @@ "functionBreakpointsNotSupported": "Les points d'arrêt de fonction ne sont pas pris en charge par ce type de débogage", "loadMoreStackFrames": "Charger plus de frames de pile", "paused": "en pause", + "process": "Processus", "running": "en cours d'exécution", "stackFrameAriaLabel": "Frame de pile {0}, ligne {1} {2}, pile des appels, débogage", "thread": "Thread", diff --git a/i18n/fra/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/fra/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index f1df6309ad9..b0bb192958e 100644 --- a/i18n/fra/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "debugConfigurationNames": "Configurations lancées dans le cadre de cette configuration \"composite\". Uniquement respecté si le type de cette configuration est \"composite\".", "debugLinuxConfiguration": "Attributs de configuration de lancement spécifiques à Linux.", "debugName": "Le nom de la configuration s'affiche dans le menu déroulant de la configuration de lancement.", "debugOSXConfiguration": "Attributs de configuration de lancement spécifiques à OS X.", diff --git a/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 82e83368ef2..c10db2490cc 100644 --- a/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "Les recommandations ne sont disponibles que pour un dossier d'espace de travail.", "OpenExtensionsFile.failed": "Impossible de créer le fichier 'extensions.json' dans le dossier '.vscode' ({0}).", - "OpenGlobalExtensionsStorageFile.failed": "Impossible de créer le fichier 'extensions.json' dans le dossier '{0}' ({1}).", + "Uninstalling": "Désinstallation en cours", "builtin": "Intégrée", "clearExtensionsInput": "Effacer l'entrée des extensions", "configureWorkspaceRecommendedExtensions": "Configurer les extensions recommandées (espace de travail)", - "deleteSure": "Voulez-vous vraiment désinstaller '{0}' ?", + "disableAction": "Désactiver", + "disableAll": "Désactiver tout", + "disableAllWorkspace": "Désactiver tout (espace de travail)", + "disableAlwaysAction.label": "Désactiver", + "disableForWorkspaceAction": "Espace de travail", + "disableForWorkspaceAction.label": "Désactiver (espace de travail)", + "disableGloballyAction": "Toujours", "enableAction": "Activer", + "enableAll": "Activer tout", + "enableAllWorkspace": "Activer tout (espace de travail)", + "enableAlwaysAction.label": "Activer", + "enableForWorkspaceAction": "Espace de travail", + "enableForWorkspaceAction.label": "Activer (espace de travail)", + "enableGloballyAction": "Toujours", "installAction": "Installer", "installExtensions": "Installer les extensions", "installVSIX": "Installer depuis un VSIX...", "installing": "Installation", "openExtensionsFolder": "Ouvrir le dossier d'extensions", - "postUninstallMessage": "{0} a été désinstallé avec succès. Redémarrez pour le désactiver.", - "restart": "Pour activer cette extension, cette fenêtre de code VS doit être redémarrée.\n\nVoulez-vous continuer ?", - "restartNow": "Redémarrer maintenant", + "postDisableMessage": "Recharger cette fenêtre pour désactiver l'extension '{0}' ?", + "postDisableTooltip": "Recharger pour désactiver", + "postEnableMessage": "Recharger cette fenêtre pour activer l'extension '{0}' ?", + "postEnableTooltip": "Recharger pour activer", + "postInstallMessage": "Recharger cette fenêtre pour activer l'extension '{0}' ?", + "postInstallTooltip": "Recharger pour activer", + "postUninstallMessage": "Recharger cette fenêtre pour désactiver l'extension '{0}' ?", + "postUninstallTooltip": "Recharger pour désactiver", + "reloadAction": "Recharger", + "reloadNow": "Recharger maintenant", "showDisabledExtensions": "Afficher les extensions désactivées", "showInstalledExtensions": "Afficher les extensions installées", "showOutdatedExtensions": "Afficher les extensions obsolètes", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "Afficher les extensions recommandées", "showWorkspaceRecommendedExtensions": "Afficher les extensions recommandées pour l'espace de travail", "toggleExtensionsViewlet": "Afficher les extensions", - "uninstall": "Désinstaller", + "uninstallAction": "Désinstaller", "updateAction": "Mettre à jour", "updateAll": "Mettre à jour toutes les extensions" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/fra/src/vs/workbench/parts/git/node/git.lib.i18n.json index 8ca568a2f40..d44d0c870fd 100644 --- a/i18n/fra/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "Impossible d'ouvrir le fichier à partir de git", "fileBinaryError": "Il semble que le fichier soit binaire. Impossible de l'ouvrir en tant que texte" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/html/browser/webview.i18n.json b/i18n/fra/src/vs/workbench/parts/html/browser/webview.i18n.json index 8b6ad71cd4e..149e3238d48 100644 --- a/i18n/fra/src/vs/workbench/parts/html/browser/webview.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/html/browser/webview.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "devtools.webview": "Développeur : outils Webview" +} \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json b/i18n/fra/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json index db4960446ea..ca2b04b101c 100644 --- a/i18n/fra/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorsAndWarnings": "{0}, erreurs et avertissements" + "errorsAndWarnings": "{0} erreurs et avertissements" } \ No newline at end of file diff --git a/i18n/fra/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/fra/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index 30d3d423ae5..c7db9122f8c 100644 --- a/i18n/fra/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "Ouvrir d'abord un fichier texte pour atteindre une ligne", "gotoLine": "Atteindre la ligne...", - "gotoLineColumnLabel": "Atteindre la ligne {0} et la colonne {1}", + "gotoLineColumnLabel": "Atteindre la ligne {0} et le caractère {1}", "gotoLineHandlerAriaLabel": "Tapez un numéro de ligne à atteindre.", "gotoLineLabel": "Atteindre la ligne {0}", "gotoLineLabelEmpty": "Tapez un numéro de ligne à atteindre.", diff --git a/i18n/fra/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json b/i18n/fra/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json index 44be6bdea82..25cb7490dfb 100644 --- a/i18n/fra/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json @@ -8,7 +8,7 @@ "array": "tableaux ({0})", "boolean": "booléens ({0})", "cannotRunGotoSymbol": "Ouvrir d'abord un fichier texte pour atteindre un symbole", - "cannotRunGotoSymbolInFile": "Malheureusement, nous n'avons pas d'informations de symboles pour le fichier", + "cannotRunGotoSymbolInFile": "Aucune information sur les symboles pour le fichier", "class": "classes ({0})", "entryAriaLabel": "{0}, symboles", "enum": "énumérations ({0})", diff --git a/i18n/fra/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/fra/src/vs/workbench/parts/update/electron-browser/update.i18n.json index d32e46b4a03..4ef9b8e7ee1 100644 --- a/i18n/fra/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/fra/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "Télécharger maintenant", + "insiderBuilds": "Builds et mises en production Insider quotidiennes !", "later": "Plus tard", + "license": "Lire la licence", + "licenseChanged": "Nos termes du contrat de licence ont changé. Prenez un instant pour les consulter.", + "neverShowAgain": "Ne plus afficher", "noUpdatesAvailable": "Aucune mise à jour n'est disponible actuellement.", "read the release notes": "Bienvenue dans {0} v{1} ! Voulez-vous lire les notes de publication ?", + "readmore": "Lire la suite", "releaseNotes": "Notes de publication", "showReleaseNotes": "Afficher les notes de publication", "thereIsUpdateAvailable": "Une mise à jour est disponible.", diff --git a/i18n/ita/extensions/typescript/out/features/bufferSyncSupport.i18n.json b/i18n/ita/extensions/typescript/out/features/bufferSyncSupport.i18n.json index 0156142fe46..d02388107aa 100644 --- a/i18n/ita/extensions/typescript/out/features/bufferSyncSupport.i18n.json +++ b/i18n/ita/extensions/typescript/out/features/bufferSyncSupport.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "close": "Chiudi", + "doNotCheckAgain": "Non eseguire più la verifica", + "moreInformation": "Altre informazioni", + "updateTscCheck": "L'impostazione utente 'typescript.check.tscVersion' è stata aggiornata ed è ora false", "versionMismatch": "Le versioni non corrispondono. Compilatore tsc globale ({0}) != servizio di linguaggio di Visual Studio Code ({1}). Potrebbero verificarsi errori di compilazione incoerente" } \ No newline at end of file diff --git a/i18n/ita/extensions/typescript/package.i18n.json b/i18n/ita/extensions/typescript/package.i18n.json index 7ca8035a4c9..c41d630159d 100644 --- a/i18n/ita/extensions/typescript/package.i18n.json +++ b/i18n/ita/extensions/typescript/package.i18n.json @@ -4,28 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "configuration.typescript": "TypeScript", - "format.insertSpaceAfterCommaDelimiter": "Consente di definire la gestione dello spazio dopo una virgola di delimitazione", - "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Consente di definire la gestione dello spazio dopo la parola chiave function per funzioni anonime", - "format.insertSpaceAfterKeywordsInControlFlowStatements": "Consente di definire la gestione dello spazio dopo le parole chiave nell'istruzione del flusso di controllo", + "configuration.typescript": "TypeScript.", + "format.insertSpaceAfterCommaDelimiter": "Consente di definire la gestione dello spazio dopo una virgola di delimitazione6", + "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Consente di definire la gestione dello spazio dopo la parola chiave function per funzioni anonime.", + "format.insertSpaceAfterKeywordsInControlFlowStatements": "Consente di definire la gestione dello spazio dopo le parole chiave nell'istruzione del flusso di controllo.", "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Consente di definire la gestione dello spazio dopo la parentesi graffa iniziale e prima della parentesi graffa finale dell'espressione JSX. Richiede TypeScript >= 2.0.6", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Consente di definire la gestione dello spazio dopo le parentesi quadre di apertura e di chiusura non vuote", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Consente di definire la gestione dello spazio dopo le parentesi tonde di apertura e di chiusura non vuote", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Consente di definire la gestione dello spazio dopo le parentesi quadre di apertura e di chiusura non vuote.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Consente di definire la gestione dello spazio dopo le parentesi tonde di apertura e di chiusura non vuote.", "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Consente di definire la gestione dello spazio dopo la parentesi graffa iniziale e prima della parentesi graffa finale della stringa del modello. Richiede TypeScript >= 2.0.6", - "format.insertSpaceAfterSemicolonInForStatements": " Consente di definire la gestione dello spazio dopo un punto e virgola in un'istruzione for", - "format.insertSpaceBeforeAndAfterBinaryOperators": "Consente di definire la gestione dello spazio dopo un operatore binario", - "format.placeOpenBraceOnNewLineForControlBlocks": "Consente di definire se una parentesi graffa di apertura viene o meno inserita su una riga per i blocchi di controllo", - "format.placeOpenBraceOnNewLineForFunctions": "Consente di definire se una parentesi graffa di apertura viene o meno inserita su una riga per le funzioni", + "format.insertSpaceAfterSemicolonInForStatements": " Consente di definire la gestione dello spazio dopo un punto e virgola in un'istruzione for.", + "format.insertSpaceBeforeAndAfterBinaryOperators": "Consente di definire la gestione dello spazio dopo un operatore binario.", + "format.placeOpenBraceOnNewLineForControlBlocks": "Consente di definire se una parentesi graffa di apertura viene o meno inserita su una riga per i blocchi di controllo.", + "format.placeOpenBraceOnNewLineForFunctions": "Consente di definire se una parentesi graffa di apertura viene o meno inserita su una riga per le funzioni.", + "javascript.format.enable": "Abilita/Disabilita il formattatore JavaScript predefinito.", "javascript.reloadProjects.title": "Ricarica progetto JavaScript", - "javascript.validate.enable": "Abilita/Disabilita la convalida JavaScript", + "javascript.validate.enable": "Abilita/Disabilita la convalida JavaScript.", "typescript.check.tscVersion": "Verifica se un compilatore TypeScript di installazione globale, ad esempio tsc, è diverso dal servizio di linguaggio TypeScript usato.", - "typescript.check.workspaceVersion": "Verifica se nell'area di lavoro è disponibile una versione di TypeScript", - "typescript.experimentalAutomaticTypeAcquisition": "Abilita l'acquisizione automatica del tipo. Richiede TypeScript >= 2.0.6 e un riavvio dopo la modifica.", + "typescript.check.workspaceVersion": "Verifica se nell'area di lavoro è disponibile una versione di TypeScript.", + "typescript.disableAutomaticTypeAcquisition": "Disabilita l'acquisizione automatica del tipo. Richiede TypeScript >= 2.0.6 e un riavvio dopo la modifica.", + "typescript.format.enable": "Abilita/Disabilita il formattatore TypeScript predefinito.", "typescript.reloadProjects.title": "Ricarica progetto TypeScript", "typescript.tsdk.desc": "Specifica il percorso della cartella che contiene i file tsserver e lib*.d.ts da usare.", "typescript.tsdk_version.desc": "Specifica la versione di tsserver. È necessario solo se tsserver non viene installato con npm.", "typescript.tsserver.experimentalAutoBuild": "Abilita la compilazione automatica sperimentale. Richiede la versione 1.9 dev o 2.x tsserver e il riavvio di Visual Studio Code dopo la modifica.", - "typescript.tsserver.trace": "Consente la traccia dell'invio dei messaggi al server di Servizi terminal", + "typescript.tsserver.trace": "Consente la traccia dell'invio dei messaggi al server di Servizi terminal.", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Completare le funzioni con la relativa firma del parametro.", - "typescript.validate.enable": "Abilita/Disabilita la convalida TypeScript" + "typescript.validate.enable": "Abilita/Disabilita la convalida TypeScript." } \ No newline at end of file diff --git a/i18n/ita/src/vs/code/electron-main/menus.i18n.json b/i18n/ita/src/vs/code/electron-main/menus.i18n.json index bb546f6c633..a10bfd06afb 100644 --- a/i18n/ita/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/ita/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "E&&sci", "miFind": "&&Trova", "miFindInFiles": "Cerca &&nei file", - "miFocusFirstGroup": "Gruppo a &&sinistra", - "miFocusSecondGroup": "Gruppo &¢rale", - "miFocusThirdGroup": "Gruppo a &&destra", + "miFocusFirstGroup": "&&Primo gruppo", + "miFocusSecondGroup": "&&Secondo gruppo", + "miFocusThirdGroup": "&&Terzo gruppo", "miForward": "&&Avanti", "miGotoDefinition": "Vai alla &&definizione", "miGotoFile": "Vai al &&file...", "miGotoLine": "Vai alla &&riga...", "miGotoSymbolInFile": "Vai al &&simbolo nel file...", "miGotoSymbolInWorkspace": "Vai al &&simbolo nell'area di lavoro...", + "miHideStatusbar": "&&Nascondi barra di stato", "miInstallingUpdate": "Installazione dell'aggiornamento...", + "miIntroductoryVideos": "&&Video introduttivi", + "miKeyboardShortcuts": "&&Riferimento per tasti di scelta rapida", "miLicense": "&&Visualizza licenza", "miMarker": "&&Problemi", - "miMoveSidebar": "&&Sposta barra laterale", + "miMoveSidebarLeft": "Sp&&osta barra laterale a sinistra", + "miMoveSidebarRight": "Sposta barra laterale a &&destra", "miNewFile": "&&Nuovo file", "miNewWindow": "&&Nuova finestra", "miNextEditor": "&&Editor successivo", @@ -84,11 +88,13 @@ "miSelectAll": "&&Seleziona tutto", "miSelectColorTheme": "&&Tema colori", "miSelectIconTheme": "Tema &&icona file", + "miShowStatusbar": "&&Mostra barra di stato", "miSplitEditor": "Dividi &&editor", "miSwitchEditor": "Cambia &&editor", "miSwitchGroup": "Cambia &&gruppo", "miToggleDebugConsole": "Console di de&&bug", "miToggleDevTools": "&&Attiva/Disattiva strumenti di sviluppo", + "miToggleEditorLayout": "Attiva/Disattiva &&layout gruppi di editor", "miToggleFullScreen": "Attiva/Disattiva sc&&hermo intero", "miToggleIntegratedTerminal": "&&Terminale integrato", "miToggleMenuBar": "Attiva/Disattiva &&barra dei menu", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "Attiva/Disattiva &&caratteri di controllo", "miToggleRenderWhitespace": "Attiva/Disattiva rendering &&spazi vuoti", "miToggleSidebar": "Attiva/Disattiva &&barra laterale", - "miToggleStatusbar": "Attiva/Disattiva &&barra di stato", "miToggleWordWrap": "Attiva/Disattiva &&ritorno a capo automatico", "miTwitter": "Seguici su T&&witter", "miUndo": "&&Annulla", diff --git a/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json index 78ecd4dd51b..b1cfa194040 100644 --- a/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/ita/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "Controlla lo stile del cursore. I valori accettati sono 'block', 'line' e 'underline'", "detectIndentation": "All'apertura di un file, `editor.tabSize` e `editor.insertSpaces` verranno rilevati in base al contenuto del file.", "editorConfigurationTitle": "Editor", + "emptySelectionClipboard": "Consente di controllare se, quando si copia senza aver effettuato una selezione, viene copiata la riga corrente.", "folding": "Controlla se per l'editor è abilitata la riduzione del codice", "fontFamily": "Controlla la famiglia di caratteri.", "fontLigatures": "Abilita i caratteri legatura", @@ -23,7 +24,7 @@ "insertSpaces": "Inserisce spazi quando viene premuto TAB. Quando `editor.detectIndentation` è attivo, questa impostazione viene sostituita in base al contenuto del file.", "insertSpaces.errorMessage": "È previsto 'boolean'. Nota: il valore \"auto\" è stato sostituito dall'impostazione `editor.detectIndentation`.", "lineHeight": "Controlla l'altezza della riga. Usare 0 per calcolare l'altezza della riga dalle dimensioni del carattere.", - "lineNumbers": "Controlla la visibilità dei numeri di riga", + "lineNumbers": "Consente di controllare la visualizzazione dei numeri di riga. I valori possibili sono 'on', 'off' e 'relative'. Con 'relative' viene visualizzato il conteggio delle righe a partire dalla posizione corrente del cursore.", "mouseWheelScrollSensitivity": "Moltiplicatore da usare sui valori `deltaX` e `deltaY` degli eventi di scorrimento della rotellina del mouse", "mouseWheelZoom": "Ingrandisce il carattere dell'editor quando si usa la rotellina del mouse e si tiene premuto CTRL", "overviewRulerLanes": "Controlla il numero di effetti che possono essere visualizzati nella stessa posizione nel righello delle annotazioni", diff --git a/i18n/ita/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/ita/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index 7a74c512978..6416b672f9e 100644 --- a/i18n/ita/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "Visualizza la Guida sull'accessibilità", - "introMsg": "Grazie per aver provato le opzioni di accessibilità sperimentali di Visual Studio Code.", + "introMsg": "Grazie per aver provato le opzioni di accessibilità di Visual Studio Code.", "outroMsg": "Per chiudere questa descrizione comando e tornare all'editor, premere ESC.", "status": "Stato:", - "tabFocusModeOffMsg": "Premere TAB in questo editor per inserire il carattere di tabulazione. Per attivare/disattivare questo comportamento, premere {0}.", - "tabFocusModeOffMsgNoKb": "Premere TAB in questo editor per spostare lo stato attivo sull'elemento con stato attivabile successivo. Il comando {0} non può essere attualmente attivato con un tasto di scelta rapida.", - "tabFocusModeOnMsg": "Premere TAB in questo editor per spostare lo stato attivo sull'elemento con stato attivabile successivo. Per attivare/disattivare questo comportamento, premere {0}.", - "tabFocusModeOnMsgNoKb": "Premere TAB in questo editor per spostare lo stato attivo sull'elemento con stato attivabile successivo. Il comando {0} non può essere attualmente attivato con un tasto di scelta rapida." + "tabFocusModeOffMsg": "Premere TAB nell'editor corrente per inserire il carattere di tabulazione. Per attivare/disattivare questo comportamento, premere {0}.", + "tabFocusModeOffMsgNoKb": "Premere TAB nell'editor corrente per inserire il carattere di tabulazione. Il comando {0} non può essere attualmente attivato con un tasto di scelta rapida.", + "tabFocusModeOnMsg": "Premere TAB nell'editor corrente per spostare lo stato attivo sull'elemento con stato attivabile successivo. Per attivare/disattivare questo comportamento, premere {0}.", + "tabFocusModeOnMsgNoKb": "Premere TAB nell'editor corrente per spostare lo stato attivo sull'elemento con stato attivabile successivo. Il comando {0} non può essere attualmente attivato con un tasto di scelta rapida." } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/ita/src/vs/editor/contrib/format/common/formatActions.i18n.json index 64b4ebfe23c..7a08a9f447f 100644 --- a/i18n/ita/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/ita/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "Formatta codice" + "formatDocument.label": "Formatta documento", + "formatSelection.label": "Selezione formato" } \ No newline at end of file diff --git a/i18n/ita/src/vs/editor/node/textMate/TMSyntax.i18n.json b/i18n/ita/src/vs/editor/node/textMate/TMSyntax.i18n.json index cce330d8da7..aa71d31f90f 100644 --- a/i18n/ita/src/vs/editor/node/textMate/TMSyntax.i18n.json +++ b/i18n/ita/src/vs/editor/node/textMate/TMSyntax.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.embeddedLanguages": "Il valore in `contributes.{0}.embeddedLanguages` non è valido. Deve essere un mapping di oggetti tra nome ambito e linguaggio. Valore specificato: {1}", "invalid.injectTo": "Il valore in `contributes.{0}.injectTo` non è valido. Deve essere una matrice di nomi di ambito del linguaggio. Valore specificato: {1}", "invalid.language": "Il linguaggio in `contributes.{0}.language` è sconosciuto. Valore specificato: {1}", "invalid.path.0": "È previsto un valore stringa in `contributes.{0}.path`. Valore specificato: {1}", "invalid.path.1": "Valore previsto di `contributes.{0}.path` ({1}) da includere nella cartella dell'estensione ({2}). L'estensione potrebbe non essere più portatile.", "invalid.scopeName": "È previsto un valore stringa in `contributes.{0}.scopeName`. Valore specificato: {1}", "vscode.extension.contributes.grammars": "Tokenizer TextMate per contributes.", + "vscode.extension.contributes.grammars.embeddedLanguages": "Mapping tra nome ambito e ID linguaggio se questa grammatica contiene linguaggi incorporati.", "vscode.extension.contributes.grammars.injectTo": "Elenco di nomi di ambito del linguaggio in cui viene inserita questa grammatica.", "vscode.extension.contributes.grammars.language": "Identificatore di linguaggio per cui si aggiunge come contributo questa sintassi.", "vscode.extension.contributes.grammars.path": "Percorso del file tmLanguage. È relativo alla cartella delle estensioni e in genere inizia con './syntaxes/'.", diff --git a/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index a2a50141348..42ba24ec119 100644 --- a/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/ita/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "Annulla", "doNotInstall": "No", "install": "Sì", "installDependeciesConfirmation": "Se si installa '{0}', verranno installate anche le relative dipendenze. Continuare?", @@ -11,6 +12,14 @@ "invalidName": "Estensione non valida: il nome del manifesto non corrisponde.", "invalidPublisher": "Estensione non valida: l'editore del manifesto non corrisponde.", "invalidVersion": "Estensione non valida: la versione del manifesto non corrisponde.", + "multipleDependentsError": "Non è possibile disinstallare l'estensione '{0}'. Alcune estensioni, tra cui '{1}' e '{2}' dipendono da tale estensione.", "notExists": "L'estensione non è stata trovata", - "restartCode": "Riavviare Code prima di reinstallare {0}." + "ok": "OK", + "restartCode": "Riavviare Code prima di reinstallare {0}.", + "singleDependentError": "Non è possibile disinstallare l'estensione '{0}'. L'estensione '{1}' dipende da tale estensione.", + "twoDependentsError": "Non è possibile disinstallare l'estensione '{0}'. Le estensioni '{1}' e '{2}' dipendono da tale estensione.", + "uninstallAll": "Tutto", + "uninstallConfirmation": "Disinstallare '{0}'?", + "uninstallDependeciesConfirmation": "Disinstallare solo '{0}' o anche le relative dipendenze?", + "uninstallOnly": "Solo" } \ No newline at end of file diff --git a/i18n/ita/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/ita/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 95a2907f569..61dc0f55139 100644 --- a/i18n/ita/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/ita/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "la proprietà `{0}` può essere omessa o deve essere di tipo `string[]`", - "extensionDescription.activationEvents2": "le proprietà `{0}` e `{1}` devono essere specificate o omesse entrambi", - "extensionDescription.empty": "La descrizione dell'estensione restituita è vuota", - "extensionDescription.engines": "la proprietà `{0}` è obbligatoria e deve essere di tipo `object`", - "extensionDescription.engines.vscode": "la proprietà `{0}` è obbligatoria e deve essere di tipo `string`", - "extensionDescription.extensionDependencies": "la proprietà `{0}` può essere omessa o deve essere di tipo `string[]`", - "extensionDescription.main1": "la proprietà `{0}` può essere omessa o deve essere di tipo `string`", - "extensionDescription.main2": "Valore previsto di `main` ({0}) da includere nella cartella dell'estensione ({1}). L'estensione potrebbe non essere più portatile.", - "extensionDescription.main3": "le proprietà `{0}` e `{1}` devono essere specificate o omesse entrambi", - "extensionDescription.name": "la proprietà `{0}` è obbligatoria e deve essere di tipo `string`", - "extensionDescription.publisher": "la proprietà `{0}` è obbligatoria e deve essere di tipo `string`", - "extensionDescription.version": "la proprietà `{0}` è obbligatoria e deve essere di tipo `string`", "vscode.extension.activationEvents": "Eventi di attivazione per l'estensione Visual Studio Code.", "vscode.extension.badges": "Matrice di notifiche da visualizzare nella barra laterale della pagina delle estensioni del Marketplace.", "vscode.extension.badges.description": "Descrizione della notifica.", @@ -24,6 +12,7 @@ "vscode.extension.categories": "Categorie usate dalla raccolta di Visual Studio Code per definire la categoria dell'estensione.", "vscode.extension.contributes": "Tutti i contributi dell'estensione Visual Studio Code rappresentati da questo pacchetto.", "vscode.extension.displayName": "Nome visualizzato per l'estensione usato nella raccolta di Visual Studio Code.", + "vscode.extension.engines.vscode": "Per le estensioni di Visual Studio Code consente di specificare la versione di Visual Studio Code con cui è compatibile l'estensione. Non può essere *. Ad esempio: ^0.10.5 indica la compatibilità con la versione minima 0.10.5 di Visual Studio Code.", "vscode.extension.extensionDependencies": "Dipendenze ad altre estensioni. L'identificatore di un'estensione è sempre ${publisher}.${name}. Ad esempio: vscode.csharp.", "vscode.extension.galleryBanner": "Banner usato nel marketplace di Visual Studio Code.", "vscode.extension.galleryBanner.color": "Colore del banner nell'intestazione pagina del marketplace di Visual Studio Code.", diff --git a/i18n/ita/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/ita/src/vs/workbench/browser/actions/openSettings.i18n.json index 9efce69bce9..0c17a756bc3 100644 --- a/i18n/ita/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "Tasti di scelta rapida predefiniti", "defaultKeybindingsHeader": "Per sovrascrivere i tasti di scelta rapida, inserirli nel file dei tasti di scelta rapida.", "defaultName": "Impostazioni predefinite", + "defaultSettingsEditor": "Editor impostazioni predefinite", "defaultSettingsHeader": "Per sovrascrivere le impostazioni, inserirli nel file delle impostazioni.", "defaultSettingsHeader2": "Per le impostazioni più usate, vedere http://go.microsoft.com/fwlink/?LinkId=808995.", "emptyKeybindingsHeader": "Inserire i tasti di scelta rapida in questo file per sovrascrivere i valori predefiniti", diff --git a/i18n/ita/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/ita/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..1c5cd090934 100644 --- a/i18n/ita/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "Layout orizzontale gruppi di editor", + "toggleEditorGroupLayout": "Attiva/Disattiva layout orizzontale/verticale gruppi di editor", + "verticalLayout": "Layout verticale gruppi di editor", + "view": "Visualizza" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 08ff06bb870..5989c967b29 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "Mostra tutti gli editor aperti", "binaryDiffEditor": "Editor diff file binari", - "centerEditorGroupPicker": "Mostra editor nel gruppo centrale", - "leftEditorGroupPicker": "Mostra editor nel gruppo a sinistra", - "rightEditorGroupPicker": "Mostra editor nel gruppo a destra", + "groupOnePicker": "Mostra editor nel primo gruppo", + "groupThreePicker": "Mostra editor nel terzo gruppo", + "groupTwoPicker": "Mostra editor nel secondo gruppo", "textDiffEditor": "Editor diff file di testo", "textEditor": "Editor di testo", "view": "Visualizza" diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index e263cb5039a..7bc2c61fc2a 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "Chiudi gli altri editor", "evenEditorGroups": "Imposta stessa larghezza per gruppo di editor", "focusActiveEditorGroup": "Sposta stato attivo sul gruppo di editor attivo", - "focusFirstEditorGroup": "Sposta stato attivo su gruppo di editor a sinistra", + "focusFirstEditorGroup": "Sposta stato attivo sul primo gruppo di editor", "focusLastEditorInStack": "Apri ultimo editor del gruppo", "focusNextGroup": "Sposta stato attivo sul gruppo successivo", "focusPreviousGroup": "Sposta stato attivo sul gruppo precedente", - "focusSecondEditorGroup": "Sposta stato attivo sul gruppo di editor al centro", - "focusThirdEditorGroup": "Sposta stato attivo sul gruppo di editor a destra", + "focusSecondEditorGroup": "Sposta stato attivo sul secondo gruppo di editor", + "focusThirdEditorGroup": "Sposta stato attivo sul terzo gruppo di editor", "keepEditor": "Mantieni editor", "maximizeEditor": "Ingrandisci gruppo di editor e nascondi barra laterale", "minimizeOtherEditorGroups": "Riduci a icona gli altri gruppi di editor", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "Sposta gruppo di editor a destra", "moveEditorLeft": "Sposta editor a sinistra", "moveEditorRight": "Sposta editor a destra", - "moveEditorToLeftGroup": "Sposta l'editor nel gruppo a sinistra", - "moveEditorToRightGroup": "Sposta l'editor nel gruppo a destra", + "moveEditorToNextGroup": "Sposta editor nel gruppo successivo", + "moveEditorToPreviousGroup": "Sposta editor nel gruppo precedente", "navigateEditorGroups": "Esplora gruppi di editor", "navigateEditorHistoryByInput": "Apri editor precedente dalla cronologia", "navigateNext": "Avanti", @@ -38,12 +38,11 @@ "openPreviousEditor": "Apri editor precedente", "openPreviousEditorInGroup": "Apri editor precedente usato di recente nel gruppo", "openToSide": "Apri lateralmente", - "removeFromEditorHistory": "Rimuovi dalla cronologia dell'editor", "reopenClosedEditor": "Riapri editor chiuso", "showAllEditors": "Mostra tutti gli editor", - "showEditorsInCenterGroup": "Mostra editor nel gruppo centrale", + "showEditorsInFirstGroup": "Mostra editor nel primo gruppo", "showEditorsInGroup": "Mostra editor nel gruppo", - "showEditorsInLeftGroup": "Mostra editor nel gruppo a sinistra", - "showEditorsInRightGroup": "Mostra editor nel gruppo a destra", + "showEditorsInSecondGroup": "Mostra editor nel secondo gruppo", + "showEditorsInThirdGroup": "Mostra editor nel terzo gruppo", "splitEditor": "Dividi editor" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index 59517523d01..5a5f8d3f889 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "Centrale", "editorOpenError": "Non è possibile aprire '{0}': {1}.", - "leftGroup": "A sinistra", - "rightGroup": "A destra" + "groupOneHorizontal": "In alto", + "groupOneVertical": "A sinistra", + "groupThreeHorizontal": "In basso", + "groupThreeVertical": "A destra", + "groupTwoHorizontal": "Al centro", + "groupTwoVertical": "Al centro" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index 88665f17c94..53b53212ca0 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0}, selezione gruppo di editor", "groupLabel": "Gruppo: {0}", - "noOpenedEditors": "L'elenco degli editor aperti è attualmente vuoto", + "noOpenedEditors": "L'elenco degli editor aperti è attualmente vuoto nel gruppo", + "noOpenedEditorsAllGroups": "L'elenco degli editor aperti è attualmente vuoto", "noResultsFound": "Non è stato trovato alcun editor aperto corrispondente", "noResultsFoundInGroup": "Nel gruppo non è stato trovato alcun editor aperto corrispondente" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/ita/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index f5a68f6dc41..4c9bf20b4e1 100644 --- a/i18n/ita/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/ita/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "Seleziona sequenza di fine riga", "selectEncoding": "Seleziona codifica", "selectLanguageMode": "Seleziona modalità linguaggio", + "showLanguageExtensions": "Cerca '{0}' nelle estensioni del Marketplace...", "singleSelection": "Ri {0}, col {1}", "singleSelectionRange": "Ri {0}, col {1} ({2} selezionate)", "spacesSize": "Spazi: {0}", diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index 2c516ae9029..f76f84082da 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "Il programma si arresterà in questo punto solo se la condizione è vera. Premere INVIO per accettare oppure ESC per annullare.", - "breakpointWidgetExpressionPlaceholder": "Interrompi quando l'espressione restituisce true", + "breakpointWidgetExpressionPlaceholder": "Interrompe quando l'espressione restituisce true. Premere 'INVIO' per accettare oppure 'ESC' per annullare.", "breakpointWidgetHitCountAriaLabel": "Il programma si arresterà in questo punto solo se viene raggiunto il numero di passaggi. Premere INVIO per accettare oppure ESC per annullare.", - "breakpointWidgetHitCountPlaceholder": "Interrompi quando viene soddisfatta la condizione del numero di passaggi", + "breakpointWidgetHitCountPlaceholder": "Interrompe quando viene soddisfatta la condizione del numero di passaggi. Premere 'INVIO' per accettare oppure 'ESC' per annullare.", "expression": "Espressione", "hitCount": "Numero di passaggi" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index dca1ab8f468..5f4ecb685c9 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "Debug: Aggiungi Punto di interruzione condizionale...", "continueDebug": "Continua", "deactivateBreakpoints": "Disattiva punti di interruzione", - "debugActionLabelAndKeybinding": "{0} ({1})", "debugAddToWatch": "Debug: Aggiungi a espressione di controllo", "debugConsoleAction": "Console di debug", "debugEvaluate": "Debug: Valuta", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "Disabilita tutti i punti di interruzione", "disconnectDebug": "Disconnetti", "editConditionalBreakpoint": "Modifica punto di interruzione...", + "editWatchExpression": "Modifica espressione", "enableAllBreakpoints": "Abilita tutti i punti di interruzione", "launchJsonNeedsConfigurtion": "Configurare o correggere 'launch.json'", "openLaunchJson": "Apri {0}", @@ -32,7 +32,6 @@ "removeBreakpoint": "Rimuovi punto di interruzione", "removeWatchExpression": "Rimuovi espressione", "renameFunctionBreakpoint": "Rinomina punto di interruzione della funzione", - "renameWatchExpression": "Rinomina espressione", "restartDebug": "Riavvia", "restartFrame": "Riavvia frame", "runToCursor": "Debug: Esegui fino al cursore", diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index 867596cc5df..8b6fc58595d 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "Consente di impostare i punti di interruzione per tutti i file, indipendentemente dall'estensione.", + "allowBreakpointsEverywhere": "Consente l'impostazione del punto di interruzione in qualsiasi file", "debug": "Debug", "debugCategory": "Debug", "debugConfigurationTitle": "Debug", "debugErrorEditor": "Errore di debug", "debugPanel": "Console di debug", - "launchConfigDoesNotExist": "La configurazione di avvio '{0}' non esiste.", - "openExplorerOnEnd": "Apre automaticamente il viewlet di esplorazione al termine di una sessione di debug.", + "openExplorerOnEnd": "Apre automaticamente il viewlet di esplorazione al termine di una sessione di debug", "toggleDebugPanel": "Console di debug", "toggleDebugViewlet": "Mostra debug", "view": "Visualizza" diff --git a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json index 911ad779641..368e891a3b2 100644 --- a/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json @@ -12,6 +12,7 @@ "functionBreakpointsNotSupported": "Punti di interruzione delle funzioni non sono supportati da questo tipo di debug", "loadMoreStackFrames": "Carica altri stack frame", "paused": "in pausa", + "process": "Processo", "running": "in esecuzione", "stackFrameAriaLabel": "Riga{1} {2} dello stack frame {0}, stack di chiamate, debug", "thread": "Thread", diff --git a/i18n/ita/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/ita/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 9ef61e287af..655422321f2 100644 --- a/i18n/ita/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "Gli elementi consigliati sono disponibili solo per una cartella dell'area di lavoro.", "OpenExtensionsFile.failed": "Non è possibile creare il file 'extensions.json' all'interno della cartella '.vscode' ({0}).", - "OpenGlobalExtensionsStorageFile.failed": "Non è possibile creare il file 'extensions.json' all'interno della cartella '{0}' ({1}).", + "Uninstalling": "Disinstallazione", "builtin": "Predefinita", "clearExtensionsInput": "Cancella input estensioni", "configureWorkspaceRecommendedExtensions": "Configura estensioni consigliate (area di lavoro)", - "deleteSure": "Disinstallare '{0}'?", + "disableAction": "Disabilita", + "disableAll": "Disabilita tutto", + "disableAllWorkspace": "Disabilita tutto (area di lavoro)", + "disableAlwaysAction.label": "Disabilita", + "disableForWorkspaceAction": "Area di lavoro", + "disableForWorkspaceAction.label": "Disabilita (area di lavoro)", + "disableGloballyAction": "Sempre", "enableAction": "Abilita", + "enableAll": "Abilita tutto", + "enableAllWorkspace": "Abilita tutto (area di lavoro)", + "enableAlwaysAction.label": "Abilita", + "enableForWorkspaceAction": "Area di lavoro", + "enableForWorkspaceAction.label": "Abilita (area di lavoro)", + "enableGloballyAction": "Sempre", "installAction": "Installa", "installExtensions": "Installa estensioni", "installVSIX": "Installa da VSIX...", "installing": "Installazione", "openExtensionsFolder": "Apri cartella estensioni", - "postUninstallMessage": "{0} è stato disinstallato. Riavviare per disattivarlo.", - "restart": "Per abilitare questa estensione, è necessario riavviare questa finestra di Visual Studio Code.\n\nContinuare?", - "restartNow": "Riavvia ora", + "postDisableMessage": "Ricaricare questa finestra per disabilitare l'estensione '{0}'?", + "postDisableTooltip": "Ricaricare per disabilitare", + "postEnableMessage": "Ricaricare questa finestra per abilitare l'estensione '{0}'?", + "postEnableTooltip": "Ricaricare per abilitare", + "postInstallMessage": "Ricaricare questa finestra per attivare l'estensione '{0}'?", + "postInstallTooltip": "Ricaricare per attivare", + "postUninstallMessage": "Ricaricare questa finestra per disattivare l'estensione '{0}'?", + "postUninstallTooltip": "Ricaricare per disattivare", + "reloadAction": "Ricarica", + "reloadNow": "Ricarica ora", "showDisabledExtensions": "Mostra estensioni disabilitate", "showInstalledExtensions": "Mostra estensioni installate", "showOutdatedExtensions": "Mostra estensioni obsolete", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "Mostra estensioni consigliate", "showWorkspaceRecommendedExtensions": "Mostra estensioni consigliate per l'area di lavoro", "toggleExtensionsViewlet": "Mostra estensioni", - "uninstall": "Disinstalla", + "uninstallAction": "Disinstalla", "updateAction": "Aggiorna", "updateAll": "Aggiorna tutte le estensioni" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/ita/src/vs/workbench/parts/git/node/git.lib.i18n.json index 6952c245dd7..b5a5af6daf1 100644 --- a/i18n/ita/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "Non è possibile aprire il file da GIT", "fileBinaryError": "Il file sembra essere binario e non può essere aperto come file di testo" } \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/html/browser/webview.i18n.json b/i18n/ita/src/vs/workbench/parts/html/browser/webview.i18n.json index 8b6ad71cd4e..145bf2139d7 100644 --- a/i18n/ita/src/vs/workbench/parts/html/browser/webview.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/html/browser/webview.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "devtools.webview": "Sviluppatore: Strumenti Webview" +} \ No newline at end of file diff --git a/i18n/ita/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/ita/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index ad12799d792..1ecb9f1beba 100644 --- a/i18n/ita/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "Aprire prima un file di testo per passare a una riga", "gotoLine": "Vai alla riga...", - "gotoLineColumnLabel": "Vai a riga {0} e a colonna {1}", + "gotoLineColumnLabel": "Vai a riga {0} e carattere {1}", "gotoLineHandlerAriaLabel": "Digitare un numero di riga a cui passare.", "gotoLineLabel": "Vai a riga {0}", "gotoLineLabelEmpty": "Digitare un numero di riga a cui passare", diff --git a/i18n/ita/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/ita/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 8d953bfa690..594a85a9f4c 100644 --- a/i18n/ita/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/ita/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "Scarica ora", + "insiderBuilds": "Build e versioni di Insider disponibili ogni giorno", "later": "In seguito", + "license": "Leggi licenza", + "licenseChanged": "I termini della licenza sono cambiati. Leggerli con attenzione.", + "neverShowAgain": "Non visualizzare più questo messaggio", "noUpdatesAvailable": "Al momento non sono disponibili aggiornamenti.", "read the release notes": "Benvenuti in {0} versione {1}. Leggere le note sulla versione?", + "readmore": "Altre informazioni", "releaseNotes": "Note sulla versione", "showReleaseNotes": "Mostra note sulla versione", "thereIsUpdateAvailable": "È disponibile un aggiornamento.", diff --git a/i18n/jpn/extensions/typescript/out/features/bufferSyncSupport.i18n.json b/i18n/jpn/extensions/typescript/out/features/bufferSyncSupport.i18n.json index 3bf9b8e27df..97bc07853d1 100644 --- a/i18n/jpn/extensions/typescript/out/features/bufferSyncSupport.i18n.json +++ b/i18n/jpn/extensions/typescript/out/features/bufferSyncSupport.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "close": "閉じる", + "doNotCheckAgain": "今後確認しない", + "moreInformation": "詳細情報", + "updateTscCheck": "ユーザー設定 'typescript.check.tscVersion' を false に更新しました", "versionMismatch": "グローバルな tsc ({0}) と VS Code の言語サービス ({1}) の間にバージョンの不一致があります。非整合のコンパイル エラーを引き起こす可能性があります" } \ No newline at end of file diff --git a/i18n/jpn/extensions/typescript/package.i18n.json b/i18n/jpn/extensions/typescript/package.i18n.json index b0f5cb46e99..3124f4179e1 100644 --- a/i18n/jpn/extensions/typescript/package.i18n.json +++ b/i18n/jpn/extensions/typescript/package.i18n.json @@ -4,28 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "configuration.typescript": "TypeScript", - "format.insertSpaceAfterCommaDelimiter": "コンマ区切り記号の後のスペース処理を定義します", - "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "匿名関数の関数キーワードの後のスペース処理を定義します", - "format.insertSpaceAfterKeywordsInControlFlowStatements": "制御フロー ステートメント内のキーワードの後のスペース処理を定義します", - "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "JSX 式の始め波かっこの後と終わり波かっこの前のスペース処理を定義します。TypeScript が 2.0.6 以上である必要があります", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "左右の空でない角かっこの間のスペース処理を定義します", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "左右の空でないかっこの間のスペース処理を定義します", - "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "テンプレート文字列の始め波かっこの後と終わり波かっこの前のスペース処理を定義します。TypeScript が 2.0.6 以上である必要があります", - "format.insertSpaceAfterSemicolonInForStatements": "for ステートメント内のセミコロンの後のスペース処理を定義します", - "format.insertSpaceBeforeAndAfterBinaryOperators": "2 項演算子の後のスペース処理を定義します", - "format.placeOpenBraceOnNewLineForControlBlocks": "新しい行にコントロール ブロックの始め中かっこを配置するかどうかを定義します", - "format.placeOpenBraceOnNewLineForFunctions": "新しい行に関数の始め中かっこを配置するかどうかを定義します", + "configuration.typescript": "TypeScript。", + "format.insertSpaceAfterCommaDelimiter": "コンマ区切り記号の後のスペース処理を定義します。", + "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "匿名関数の関数キーワードの後のスペース処理を定義します。", + "format.insertSpaceAfterKeywordsInControlFlowStatements": "制御フロー ステートメント内のキーワードの後のスペース処理を定義します。", + "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "JSX 式の始め波かっこの後と終わり波かっこの前のスペース処理を定義します。TypeScript が 2.0.6 以上である必要があります。", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "左右の空でない角かっこの間のスペース処理を定義します。", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "左右の空でないかっこの間のスペース処理を定義します。", + "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "テンプレート文字列の始め波かっこの後と終わり波かっこの前のスペース処理を定義します。TypeScript が 2.0.6 以上である必要があります。", + "format.insertSpaceAfterSemicolonInForStatements": " for ステートメント内のセミコロンの後のスペース処理を定義します。", + "format.insertSpaceBeforeAndAfterBinaryOperators": "2 項演算子の後のスペース処理を定義します。", + "format.placeOpenBraceOnNewLineForControlBlocks": "新しい行にコントロール ブロックの始め波かっこを配置するかどうかを定義します。", + "format.placeOpenBraceOnNewLineForFunctions": "新しい行に関数の始め波かっこを配置するかどうかを定義します。", + "javascript.format.enable": "既定の JavaScript フォーマッタを有効/無効にします。", "javascript.reloadProjects.title": "JavaScript プロジェクトを再度読み込みます", - "javascript.validate.enable": "JavaScript の検証を有効/無効にします", + "javascript.validate.enable": "JavaScript の検証を有効/無効にします。", "typescript.check.tscVersion": "グローバル インストール TypeScript コンパイラ (tsc など) が、使用された TypeScript 言語サービスと異なっているかどうかを確認します。", - "typescript.check.workspaceVersion": "TypeScript バージョンをワークスペースで使用できるかどうかを確認する", - "typescript.experimentalAutomaticTypeAcquisition": "型の自動取得を有効にします。TypeScript が 2.0.6 以上であり、変更後に再起動する必要があります。", + "typescript.check.workspaceVersion": "TypeScript バージョンをワークスペースで使用できるかどうかを確認します。", + "typescript.disableAutomaticTypeAcquisition": "種類の自動的な取得を無効にします。変更後、TypeScript 2.0.6 以降と再起動が必要です。", + "typescript.format.enable": "既定の TypeScript フォーマッタを有効/無効にします。", "typescript.reloadProjects.title": "TypeScript プロジェクトを再度読み込みます", "typescript.tsdk.desc": "使用する tsserver と lib*.d.ts ファイルが含まれているフォルダーのパスを指定します。", "typescript.tsdk_version.desc": "TS サーバーのバージョンを指定します。TS サーバーが NPM でインストールされていない場合のみ必要です。", "typescript.tsserver.experimentalAutoBuild": "試験的な自動ビルドを有効にします。1.9 dev または 2.x tsserver バージョンと、変更後に VS Code の再起動が必要です。", - "typescript.tsserver.trace": "TS サーバーに送信されるメッセージのトレースをオンにします", + "typescript.tsserver.trace": "TS サーバーに送信されるメッセージのトレースを有効にします。", "typescript.useCodeSnippetsOnMethodSuggest.dec": "パラメーター シグネチャを含む完全な関数。", - "typescript.validate.enable": "TypeScript の検証を有効/無効にします" + "typescript.validate.enable": "TypeScript の検証を有効/無効にします。" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/code/electron-main/menus.i18n.json b/i18n/jpn/src/vs/code/electron-main/menus.i18n.json index ab485bfaf26..897e1e5c447 100644 --- a/i18n/jpn/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/jpn/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "終了(&&X)", "miFind": "検索(&&F)", "miFindInFiles": "ファイル内を検索(&&I)", - "miFocusFirstGroup": "左のグループ(&&L)", - "miFocusSecondGroup": "センター グループ(&&C)", - "miFocusThirdGroup": "右のグループ(&&R)", + "miFocusFirstGroup": "最初のグループ(&&F)", + "miFocusSecondGroup": "2 番目のグループ(&&S)", + "miFocusThirdGroup": "3 番目のグループ(&&T)", "miForward": "転送(&&F)", "miGotoDefinition": "定義に移動(&&D)", "miGotoFile": "ファイルに移動(&&F)...", "miGotoLine": "行に移動(&&L)...", "miGotoSymbolInFile": "ファイル内のシンボルへ移動(&&S)...", "miGotoSymbolInWorkspace": "ワークスペース内のシンボルへ移動(&&W)...", + "miHideStatusbar": "ステータス バーを非表示にする(&&H)", "miInstallingUpdate": "更新プログラムをインストールしています...", - "miLicense": "ライセンスを表示(&&V)", + "miIntroductoryVideos": "紹介ビデオ(&&V)", + "miKeyboardShortcuts": "キーボード ショートカットの参照(&&K)", + "miLicense": "ライセンスの表示(&&L)", "miMarker": "問題(&&P)", - "miMoveSidebar": "サイドバーを移動(&&M)", + "miMoveSidebarLeft": "サイドバーを左へ移動(&&M)", + "miMoveSidebarRight": "サイドバーを右へ移動(&&M)", "miNewFile": "新規ファイル(&&N)", "miNewWindow": "新しいウィンドウ(&&N)", "miNextEditor": "次のエディター(&&N)", @@ -84,11 +88,13 @@ "miSelectAll": "すべて選択(&&S)", "miSelectColorTheme": "配色テーマ(&&C)", "miSelectIconTheme": "ファイル アイコンのテーマ(&&I)", + "miShowStatusbar": "ステータス バーの表示(&&S)", "miSplitEditor": "エディターを分割(&&E)", "miSwitchEditor": "エディターの切り替え(&&E)", "miSwitchGroup": "グループの切り替え(&&G)", "miToggleDebugConsole": "デバッグ コンソール(&&B)", "miToggleDevTools": "開発者ツールの切り替え(&&T)", + "miToggleEditorLayout": "エディター グループ レイアウトの切り替え(&&L)", "miToggleFullScreen": "全画面表示の切り替え(&&F)", "miToggleIntegratedTerminal": "統合ターミナル(&&I)", "miToggleMenuBar": "メニュー バーの切り替え(&&B)", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "制御文字の切り替え(&&C)", "miToggleRenderWhitespace": "空白文字の表示の切り替え(&&R)", "miToggleSidebar": "サイドバーの切り替え(&&T)", - "miToggleStatusbar": "ステータス バーの表示切り替え(&&T)", "miToggleWordWrap": "折り返しの切り替え(&&W)", "miTwitter": "ツイッターに参加(&&J)", "miUndo": "元に戻す(&&U)", diff --git a/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json index b999bdc5b10..9c5ed8641eb 100644 --- a/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/jpn/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "カーソルのスタイルを制御します。指定できる値は 'block'、'line'、'underline' です", "detectIndentation": "ファイルを開くと、そのファイルの内容に基づいて `editor.tabSize` と `editor.insertSpaces` が検出されます。", "editorConfigurationTitle": "エディター", + "emptySelectionClipboard": "選択範囲を指定しないでコピーする場合に現在の行をコピーするかどうかを制御します。", "folding": "エディターでコードの折りたたみを有効にするかどうかを制御します", "fontFamily": "フォント ファミリを制御します。", "fontLigatures": "フォントの合字を使用します", @@ -23,7 +24,7 @@ "insertSpaces": "Tab キーを押すとスペースが挿入されます。`editor.detectIndentation` がオンの場合、この設定はファイル コンテンツに基づいて上書きされます。", "insertSpaces.errorMessage": "'boolean' が必要です。`editor.detectIndentation` 設定によって値 \"auto\" が置き換えられていることに注意してください。", "lineHeight": "行の高さを制御します。fontSize に基づいて lineHeight を計算する場合には、0 を使用します。", - "lineNumbers": "行番号の表示を制御します", + "lineNumbers": "行番号の表示を制御します。使用可能な値は、'on'、'off'、および 'relative' です。'relative' は現在のカーソル位置からの行数を示します。", "mouseWheelScrollSensitivity": "マウス ホイール スクロール イベントの `deltaX` と `deltaY` で使用される乗数", "mouseWheelZoom": "Ctrl キーを押しながらマウス ホイールを使用してエディターのフォントをズームします", "overviewRulerLanes": "概要ルーラーの同じ位置に表示できる装飾の数を制御します", diff --git a/i18n/jpn/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/jpn/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index e8a675d3a8f..af3e5a282fa 100644 --- a/i18n/jpn/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "アクセシビリティのヘルプを表示します", - "introMsg": "VS Code の実験用アクセシビリティ オプションをご利用いただき、ありがとうございます。", + "introMsg": "VS Code のアクセシビリティ オプションをご利用いただき、ありがとうございます。", "outroMsg": "Esc キーを押すと、ヒントを消してエディターに戻ることができます。", "status": "ステータス:", - "tabFocusModeOffMsg": "このエディターで Tab キーを押すと、タブ文字が挿入されます。{0} を押すと、この動作が切り替わります。", - "tabFocusModeOffMsgNoKb": "このエディターで Tab キーを押すと、次のフォーカス可能な要素にフォーカスを移動します。コマンド {0} は、キー バインドでは現在トリガーできません。", - "tabFocusModeOnMsg": "このエディターで Tab キーを押すと、次のフォーカス可能な要素にフォーカスを移動します。{0} を押すと、この動作が切り替わります。", - "tabFocusModeOnMsgNoKb": "このエディターで Tab キーを押すと、次のフォーカス可能な要素にフォーカスを移動します。コマンド {0} は、キー バインドでは現在トリガーできません。" + "tabFocusModeOffMsg": "現在のエディターで Tab キーを押すと、タブ文字が挿入されます。{0} を押すと、この動作が切り替わります。", + "tabFocusModeOffMsgNoKb": "現在のエディターで Tab キーを押すと、タブ文字が挿入されます。コマンド {0} は、キー バインドでは現在トリガーできません。", + "tabFocusModeOnMsg": "現在のエディターで Tab キーを押すと、次のフォーカス可能な要素にフォーカスを移動します。{0} を押すと、この動作が切り替わります。", + "tabFocusModeOnMsgNoKb": "現在のエディターで Tab キーを押すと、次のフォーカス可能な要素にフォーカスを移動します。コマンド {0} は、キー バインドでは現在トリガーできません。" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/jpn/src/vs/editor/contrib/format/common/formatActions.i18n.json index 1774a740981..a7bee698b3d 100644 --- a/i18n/jpn/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/jpn/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "コードのフォーマット" + "formatDocument.label": "ドキュメントのフォーマット", + "formatSelection.label": "選択範囲のフォーマット" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/editor/node/textMate/TMSyntax.i18n.json b/i18n/jpn/src/vs/editor/node/textMate/TMSyntax.i18n.json index 273bed17a38..f37065cf235 100644 --- a/i18n/jpn/src/vs/editor/node/textMate/TMSyntax.i18n.json +++ b/i18n/jpn/src/vs/editor/node/textMate/TMSyntax.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.embeddedLanguages": "`contributes.{0}.embeddedLanguages` の値が無効です。スコープ名から言語へのオブジェクト マップである必要があります。指定された値: {1}", "invalid.injectTo": "`contributes.{0}.injectTo` の値が無効です。言語の範囲名の配列である必要があります。指定された値: {1}", "invalid.language": "`contributes.{0}.language` で不明な言語です。提供された値: {1}", "invalid.path.0": "`contributes.{0}.path` に文字列が必要です。提供された値: {1}", "invalid.path.1": "拡張機能のフォルダー ({2}) の中に `contributes.{0}.path` ({1}) が含まれている必要があります。これにより拡張を移植できなくなる可能性があります。", "invalid.scopeName": "`contributes.{0}.scopeName` には文字列が必要です。提供された値: {1}", "vscode.extension.contributes.grammars": "TextMate トークナイザーを提供します。", + "vscode.extension.contributes.grammars.embeddedLanguages": "この文法に言語が埋め込まれている場合は、言語 ID に対するスコープ名のマップ。", "vscode.extension.contributes.grammars.injectTo": "この文法が挿入される言語の範囲名の一覧。", "vscode.extension.contributes.grammars.language": "この構文の提供先の言語識別子です。", "vscode.extension.contributes.grammars.path": "tmLanguage ファイルのパス。拡張機能フォルダーの相対パスであり、通常 './syntaxes/' で始まります。", diff --git a/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 2156eb8dcf7..4dea71924ee 100644 --- a/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/jpn/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "キャンセル", "doNotInstall": "いいえ", "install": "はい", "installDependeciesConfirmation": "'{0}' をインストールすると、その依存関係もインストールされます。続行してもよろしいですか?", @@ -11,6 +12,14 @@ "invalidName": "正しくない拡張機能: マニフェスト名が一致しません。", "invalidPublisher": "正しくない拡張機能: マニフェストのパブリッシャーが一致しません。", "invalidVersion": "正しくない拡張機能: マニフェストのバージョンが一致しません。", + "multipleDependentsError": "拡張機能 '{0}' をアンインストールできません。拡張機能 '{1}'、'{2}'、その他がこの拡張機能に依存しています。", "notExists": "拡張機能を見つけられませんでした", - "restartCode": "{0} を再インストールする前に、Code を再起動してください。" + "ok": "OK", + "restartCode": "{0} を再インストールする前に、Code を再起動してください。", + "singleDependentError": "拡張機能 '{0}' をアンインストールできません。拡張機能 '{1}' がこの拡張機能に依存しています。", + "twoDependentsError": "拡張機能 '{0}' をアンインストールできません。拡張機能 '{1}' と '{2}' がこの拡張機能に依存しています。", + "uninstallAll": "すべて", + "uninstallConfirmation": "'{0}' をアンインストールしてもよろしいですか?", + "uninstallDependeciesConfirmation": "'{0}' のみをアンインストールしますか、または依存関係もアンインストールしますか?", + "uninstallOnly": "限定" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/jpn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 67427ecd518..1eedafd7c54 100644 --- a/i18n/jpn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/jpn/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "プロパティ `{0}` は省略するか、型 `string[]` にする必要があります", - "extensionDescription.activationEvents2": "プロパティ `{0}` と `{1}` は、両方とも指定するか両方とも省略しなければなりません", - "extensionDescription.empty": "空の拡張機能の説明を入手しました", - "extensionDescription.engines": "プロパティ `{0}` は必須で、型 `object` でなければなりません", - "extensionDescription.engines.vscode": "プロパティ `{0}` は必須で、型 `string` でなければなりません", - "extensionDescription.extensionDependencies": "プロパティ `{0}` は省略するか、型 `string[]` にする必要があります", - "extensionDescription.main1": "プロパティ `{0}` は省略するか、型 `string` にする必要があります", - "extensionDescription.main2": "拡張機能のフォルダー ({1}) の中に `main` ({0}) が含まれることが予期されます。これにより拡張機能を移植できなくなる可能性があります。", - "extensionDescription.main3": "プロパティ `{0}` と `{1}` は、両方とも指定するか両方とも省略しなければなりません", - "extensionDescription.name": "プロパティ `{0}` は必須で、型 `string` でなければなりません", - "extensionDescription.publisher": "プロパティ `{0}` は必須で、型 `string` でなければなりません", - "extensionDescription.version": "プロパティ `{0}` は必須で、型 `string` でなければなりません", "vscode.extension.activationEvents": "VS Code 拡張機能のアクティブ化イベント。", "vscode.extension.badges": "Marketplace の拡張機能ページのサイドバーに表示されるバッジの配列。", "vscode.extension.badges.description": "バッジの説明。", @@ -24,6 +12,7 @@ "vscode.extension.categories": "VS Code ギャラリーで拡張機能の分類に使用されるカテゴリ。", "vscode.extension.contributes": "このパッケージで表される VS Code 拡張機能のすべてのコントリビューション。", "vscode.extension.displayName": "VS Code ギャラリーで使用される拡張機能の表示名。", + "vscode.extension.engines.vscode": "VS Code 拡張機能の場合、拡張機能と互換性のある VS Code バージョンを指定します。* を指定することはできません。たとえば、^0.10.5 は最小の VS Code バージョン 0.10.5 との互換性を示します。", "vscode.extension.extensionDependencies": "他の拡張機能に対する依存関係。拡張機能の識別子は常に ${publisher}.${name} です。例: vscode.csharp。", "vscode.extension.galleryBanner": "VS Code マーケットプレースで使用されるバナー。", "vscode.extension.galleryBanner.color": "VS Code マーケットプレース ページ ヘッダー上のバナーの色。", diff --git a/i18n/jpn/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/jpn/src/vs/workbench/browser/actions/openSettings.i18n.json index ee3bbae09cb..6143fbaeac4 100644 --- a/i18n/jpn/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "既定のキーボード ショートカット", "defaultKeybindingsHeader": "キー バインド ファイル内にキー バインドを挿入して、キー バインドを上書きします。", "defaultName": "既定の設定", + "defaultSettingsEditor": "既定の設定エディター", "defaultSettingsHeader": "設定ファイル内に設定を挿入して、設定を上書きします。", "defaultSettingsHeader2": "最もよく使用される設定については、http://go.microsoft.com/fwlink/?LinkId=808995 をご覧ください。", "emptyKeybindingsHeader": "既定値を上書きするには、このファイル内にキー バインドを挿入します", diff --git a/i18n/jpn/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/jpn/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..6fea567886f 100644 --- a/i18n/jpn/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "エディターグループの横レイアウト", + "toggleEditorGroupLayout": "エディターグループの縦/横レイアウトを切り替える", + "verticalLayout": "エディターグループの縦レイアウト", + "view": "表示" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 4eb8d10b500..1187daed7fe 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "開いているエディターをすべて表示する", "binaryDiffEditor": "バイナリ差分エディター", - "centerEditorGroupPicker": "エディターを中央のグループに表示する", - "leftEditorGroupPicker": "エディターを左のグループに表示する", - "rightEditorGroupPicker": "エディターを右のグループに表示する", + "groupOnePicker": "最初のグループでエディターを表示する", + "groupThreePicker": "3 番目のグループでエディターを表示する", + "groupTwoPicker": "2 番目のグループでエディターを表示する", "textDiffEditor": "テキスト差分エディター", "textEditor": "テキスト エディター", "view": "表示" diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 1233865f2a9..9d2ab11a4a1 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "その他のエディターを閉じる", "evenEditorGroups": "エディター グループの幅を等間隔に設定する", "focusActiveEditorGroup": "アクティブなエディター グループにフォーカス", - "focusFirstEditorGroup": "左側のエディター グループにフォーカス", + "focusFirstEditorGroup": "最初のエディター グループにフォーカス", "focusLastEditorInStack": "グループ内の最後のエディターを開く", "focusNextGroup": "次のグループにフォーカス", "focusPreviousGroup": "前のグループにフォーカス", - "focusSecondEditorGroup": "中央のエディター グループにフォーカス", - "focusThirdEditorGroup": "右側のエディター グループにフォーカス", + "focusSecondEditorGroup": "2 番目のエディター グループにフォーカス", + "focusThirdEditorGroup": "3 番目のエディター グループにフォーカス", "keepEditor": "エディターを保持", "maximizeEditor": "エディター グループを最大化してサイドバーを非表示にする", "minimizeOtherEditorGroups": "他のエディター グループを最小化する", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "エディター グループを右側に移動する", "moveEditorLeft": "エディターを左へ移動", "moveEditorRight": "エディターを右へ移動", - "moveEditorToLeftGroup": "エディターを左側のグループに移動", - "moveEditorToRightGroup": "エディターを右側のグループに移動", + "moveEditorToNextGroup": "エディターを次のグループに移動", + "moveEditorToPreviousGroup": "エディターを前のグループに移動", "navigateEditorGroups": "エディター グループ間で移動する", "navigateEditorHistoryByInput": "履歴から以前のエディターを開く", "navigateNext": "次に進む", @@ -38,12 +38,11 @@ "openPreviousEditor": "以前のエディターを開く", "openPreviousEditorInGroup": "グループ内の最近使用したエディターのうち前のエディターを開く", "openToSide": "横に並べて開く", - "removeFromEditorHistory": "エディター履歴から削除する", "reopenClosedEditor": "閉じたエディターを再度開く", "showAllEditors": "すべてのエディターを表示する", - "showEditorsInCenterGroup": "エディターを中央のグループに表示する", + "showEditorsInFirstGroup": "最初のグループでエディターを表示する", "showEditorsInGroup": "エディターをグループに表示する", - "showEditorsInLeftGroup": "エディターを左のグループに表示する", - "showEditorsInRightGroup": "エディターを右のグループに表示する", + "showEditorsInSecondGroup": "2 番目のグループでエディターを表示する", + "showEditorsInThirdGroup": "3 番目のグループでエディターを表示する", "splitEditor": "エディターの分割" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index d63f69d7ad5..b9508bf22fe 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "中央", "editorOpenError": "'{0}' を開くことができません: {1}。", - "leftGroup": "左", - "rightGroup": "右" + "groupOneHorizontal": "上", + "groupOneVertical": "左", + "groupThreeHorizontal": "下", + "groupThreeVertical": "右", + "groupTwoHorizontal": "中央", + "groupTwoVertical": "中央" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index f29e83ce366..c619081ec80 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0}、エディター グループの選択", "groupLabel": "グループ: {0}", - "noOpenedEditors": "開いているエディターの一覧は現在、空です", + "noOpenedEditors": "グループ内で開いているエディターの一覧は現在、空です", + "noOpenedEditorsAllGroups": "開いているエディターの一覧は現在、空です", "noResultsFound": "一致する開いているエディターがありません", "noResultsFoundInGroup": "グループ内に一致する開いているエディターがありません" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 74ca90f5794..77cdd8603b4 100644 --- a/i18n/jpn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/jpn/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "改行コードの選択", "selectEncoding": "エンコードの選択", "selectLanguageMode": "言語モードの選択", + "showLanguageExtensions": "'{0}' の Marketplace の拡張機能を検索する ...", "singleSelection": "行 {0}、列 {1}", "singleSelectionRange": "行 {0}、列 {1} ({2} 個選択)", "spacesSize": "スペース: {0}", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index 98145681fce..3e051e42a2a 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "この条件が true の場合にのみプログラムはこの位置で停止します。Enter を押して受け入れるか、Esc を押して取り消します。", - "breakpointWidgetExpressionPlaceholder": "式が true と評価される場合にブレークする", + "breakpointWidgetExpressionPlaceholder": "式が true と評価される場合に中断します。'Enter' を押して受け入れるか 'Esc' を押して取り消します。", "breakpointWidgetHitCountAriaLabel": "ヒット カウントが満たされる場合にのみプログラムはこの位置で停止します。Enter を押して受け入れるか、Esc を押して取り消します。", - "breakpointWidgetHitCountPlaceholder": "ヒット カウント条件が満たされる場合にブレークする", + "breakpointWidgetHitCountPlaceholder": "ヒット カウント条件が満たされる場合に中断します。'Enter' を押して受け入れるか 'Esc' を押して取り消します。", "expression": "式", "hitCount": "ヒット カウント" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index c13ac24cecb..5f3f133b180 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "デバッグ: 条件付きブレークポイントの追加...", "continueDebug": "続行", "deactivateBreakpoints": "ブレークポイントの非アクティブ化", - "debugActionLabelAndKeybinding": "{0} ({1})", "debugAddToWatch": "デバッグ: ウォッチに追加", "debugConsoleAction": "デバッグ コンソール", "debugEvaluate": "デバッグ: 評価", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "すべてのブレークポイントを無効にする", "disconnectDebug": "切断", "editConditionalBreakpoint": "ブレークポイントの編集...", + "editWatchExpression": "式の編集", "enableAllBreakpoints": "すべてのブレークポイントを有効にする", "launchJsonNeedsConfigurtion": "'launch.json' を構成または修正してください", "openLaunchJson": "{0} を開く", @@ -32,7 +32,6 @@ "removeBreakpoint": "ブレークポイントの削除", "removeWatchExpression": "式の削除", "renameFunctionBreakpoint": "関数ブレークポイントの名前変更", - "renameWatchExpression": "式の名前変更", "restartDebug": "再起動", "restartFrame": "フレームの再起動", "runToCursor": "デバッグ: カーソル行の前まで実行", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index 0264044f7b6..aefff7838b7 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "拡張子にかかわらず、すべてのファイルに対してブレークポイントを設定できるようにします。", + "allowBreakpointsEverywhere": "任意のファイルにブレークポイントを設定できるようにする", "debug": "デバッグ", "debugCategory": "デバッグ", "debugConfigurationTitle": "デバッグ", "debugErrorEditor": "デバッグ エラー", "debugPanel": "デバッグ コンソール", - "launchConfigDoesNotExist": "起動の構成 '{0}' がありません。", - "openExplorerOnEnd": "デバッグ セッションの終わりに Explorer ビューレットを自動的に開きます。", + "openExplorerOnEnd": "デバッグ セッションの終わりに Explorer ビューレットを自動的に開く", "toggleDebugPanel": "デバッグ コンソール", "toggleDebugViewlet": "デバッグの表示", "view": "表示" diff --git a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json index f97e5c17700..20378313a94 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json @@ -12,6 +12,7 @@ "functionBreakpointsNotSupported": "このデバッグの種類では関数ブレークポイントはサポートされていません", "loadMoreStackFrames": "スタック フレームをさらに読み込む", "paused": "一時停止", + "process": "プロセス", "running": "実行中", "stackFrameAriaLabel": "スタック フレーム {0} 行 {1} {2}、呼び出しスタック、デバッグ", "thread": "スレッド", diff --git a/i18n/jpn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/jpn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 562d89209a5..9314ade3838 100644 --- a/i18n/jpn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "debugConfigurationNames": "この \"コンポジット\" 構成の一部として起動される構成。この構成の種類が \"コンポジット\" の場合にのみ有効です。", "debugLinuxConfiguration": "Linux 固有の起動構成の属性。", "debugName": "構成の名前。起動構成のドロップダウン メニューに表示されます。", "debugOSXConfiguration": "OS X 固有の起動構成の属性。", diff --git a/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index c0df2e4ce1e..c813eaed885 100644 --- a/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "推奨事項はワークスペース フォルダーでのみ利用可能です。", "OpenExtensionsFile.failed": "'.vscode' ファルダー ({0}) 内に 'extensions.json' ファイルを作成できません。", - "OpenGlobalExtensionsStorageFile.failed": "'{0}' フォルダー ({1}) 内に 'extensions.json' ファイルを作成できませんでした。", + "Uninstalling": "アンインストールしています", "builtin": "ビルトイン", "clearExtensionsInput": "拡張機能の入力のクリア", "configureWorkspaceRecommendedExtensions": "お勧めの拡張機能の構成 (ワークスペース)", - "deleteSure": "'{0}' をアンインストールしてもよろしいですか?", + "disableAction": "無効にする", + "disableAll": "すべて無効にする", + "disableAllWorkspace": "すべて無効にする (ワークスペース)", + "disableAlwaysAction.label": "無効にする", + "disableForWorkspaceAction": "ワークスペース", + "disableForWorkspaceAction.label": "無効にする (ワークスペース)", + "disableGloballyAction": "常に行う", "enableAction": "有効", + "enableAll": "すべて有効にする", + "enableAllWorkspace": "すべて有効にする (ワークスペース)", + "enableAlwaysAction.label": "有効にする", + "enableForWorkspaceAction": "ワークスペース", + "enableForWorkspaceAction.label": "有効にする (ワークスペース)", + "enableGloballyAction": "常に行う", "installAction": "インストール", "installExtensions": "拡張機能のインストール", "installVSIX": "VSIX からのインストール...", "installing": "インストールしています", "openExtensionsFolder": "拡張機能フォルダーを開く", - "postUninstallMessage": "'{0}' は正常にアンインストールされました。非アクティブ化するには再起動してください。", - "restart": "この拡張機能を有効にするには、VS Code のこのウィンドウを再起動する必要があります。\n\n続行しますか?", - "restartNow": "今すぐ再起動", + "postDisableMessage": "このウィンドウを再度読み込んで '{0}' 拡張機能を無効にしますか?", + "postDisableTooltip": "読み込んで無効にする", + "postEnableMessage": "このウィンドウを再度読み込んで '{0}' 拡張機能を有効にしますか?", + "postEnableTooltip": "読み込んで有効にする", + "postInstallMessage": "このウィンドウを再度読み込んで '{0}' 拡張機能をアクティブにしますか?", + "postInstallTooltip": "読み込んでアクティブにする", + "postUninstallMessage": "このウィンドウを再度読み込んで '{0}' 拡張機能を非アクティブ化しますか?", + "postUninstallTooltip": "読み込んで非アクティブ化する", + "reloadAction": "再度読み込む", + "reloadNow": "今すぐ再度読み込む", "showDisabledExtensions": "無効な拡張機能の表示", "showInstalledExtensions": "インストール済みの拡張機能の表示", "showOutdatedExtensions": "古くなった拡張機能の表示", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "お勧めの拡張機能を表示", "showWorkspaceRecommendedExtensions": "ワークスペースのおすすめの拡張機能を表示", "toggleExtensionsViewlet": "拡張機能を表示する", - "uninstall": "アンインストール", + "uninstallAction": "アンインストール", "updateAction": "更新", "updateAll": "すべての拡張機能を更新します" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/jpn/src/vs/workbench/parts/git/node/git.lib.i18n.json index 26fc5404882..99992ff6e22 100644 --- a/i18n/jpn/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "Git からファイルを開くことができません", "fileBinaryError": "ファイルはバイナリのようなので、テキストとして開くことができません" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/html/browser/webview.i18n.json b/i18n/jpn/src/vs/workbench/parts/html/browser/webview.i18n.json index 8b6ad71cd4e..7f5ae20d7db 100644 --- a/i18n/jpn/src/vs/workbench/parts/html/browser/webview.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/html/browser/webview.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "devtools.webview": "開発者: Web ビュー ツール" +} \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json b/i18n/jpn/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json index fca7880c1dd..47f77083978 100644 --- a/i18n/jpn/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.i18n.json @@ -4,5 +4,5 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "errorsAndWarnings": "{0} エラーと警告" + "errorsAndWarnings": "{0} 件のエラーと警告" } \ No newline at end of file diff --git a/i18n/jpn/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/jpn/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index 3f033ff1972..030c7c108d2 100644 --- a/i18n/jpn/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "まずテキスト ファイルを開いてから指定行に移動します", "gotoLine": "指定行へ移動...", - "gotoLineColumnLabel": "行 {0} 列 {1} へ移動", + "gotoLineColumnLabel": "行 {0} 文字 {1} へ移動", "gotoLineHandlerAriaLabel": "移動先の行番号を入力してください。", "gotoLineLabel": "行 {0} へ移動", "gotoLineLabelEmpty": "移動先の行番号を入力してください", diff --git a/i18n/jpn/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json b/i18n/jpn/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json index 58fc1218327..80775faeae5 100644 --- a/i18n/jpn/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json @@ -8,7 +8,7 @@ "array": "配列 ({0})", "boolean": "ブール値 ({0})", "cannotRunGotoSymbol": "まずテキスト ファイルを開いてからシンボルへ移動します", - "cannotRunGotoSymbolInFile": "残念ながらファイルのシンボル情報がありません", + "cannotRunGotoSymbolInFile": "ファイルのシンボル情報がありません", "class": "クラス ({0})", "entryAriaLabel": "{0}、シンボル", "enum": "列挙型 ({0})", diff --git a/i18n/jpn/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/jpn/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 795d31e5be7..1ffb13d0c33 100644 --- a/i18n/jpn/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/jpn/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "今すぐダウンロード", + "insiderBuilds": "Insider ビルドが毎日リリースされます!", "later": "後で", + "license": "ライセンスの閲覧", + "licenseChanged": "ライセンス条項が変更されました。内容をご確認ください。", + "neverShowAgain": "今後は表示しない", "noUpdatesAvailable": "現在入手可能な更新はありません。", "read the release notes": "{0} v{1} へようこそ! リリース ノートを確認しますか?", + "readmore": "詳細を参照", "releaseNotes": "リリース ノート", "showReleaseNotes": "リリース ノートの表示", "thereIsUpdateAvailable": "利用可能な更新プログラムがあります。", diff --git a/i18n/kor/extensions/typescript/out/features/bufferSyncSupport.i18n.json b/i18n/kor/extensions/typescript/out/features/bufferSyncSupport.i18n.json index fd8c9eae4f4..5f11993b3f1 100644 --- a/i18n/kor/extensions/typescript/out/features/bufferSyncSupport.i18n.json +++ b/i18n/kor/extensions/typescript/out/features/bufferSyncSupport.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "close": "닫기", + "doNotCheckAgain": "다시 확인 안 함", + "moreInformation": "추가 정보", + "updateTscCheck": "사용자 설정 'typescript.check.tscVersion'을 false로 업데이트했습니다.", "versionMismatch": "버전이 일치하지 않습니다. 전역 tsc({0})가 VS 코드의 언어 서비스({1})와 다릅니다. 일관되지 않은 컴파일 오류가 발생할 수 있습니다." } \ No newline at end of file diff --git a/i18n/kor/extensions/typescript/package.i18n.json b/i18n/kor/extensions/typescript/package.i18n.json index 3d6c7281829..ea05f623683 100644 --- a/i18n/kor/extensions/typescript/package.i18n.json +++ b/i18n/kor/extensions/typescript/package.i18n.json @@ -4,28 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "configuration.typescript": "TypeScript", + "configuration.typescript": "TypeScript.", "format.insertSpaceAfterCommaDelimiter": "쉼표 구분 기호 뒤에 오는 공백 처리를 정의합니다.", "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "익명 함수의 function 키워드 뒤에 오는 공백 처리를 정의합니다.", "format.insertSpaceAfterKeywordsInControlFlowStatements": "제어 흐름 문의 키워드 뒤에 오는 공백 처리를 정의합니다.", - "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "JSX 식의 여는 중괄호 뒤와 닫는 중괄호 앞의 공백 처리를 정의합니다. TypeScript 2.0.6 이상이 필요합니다.", + "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "JSX 식의 여는 중괄호 뒤와 닫는 중괄호 앞의 공백 처리를 정의합니다. TypeScript >= 2.0.6이 필요합니다.", "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "비어 있지 않은 여는 대괄호 뒤와 닫는 대괄호 앞에 오는 공백 처리를 정의합니다.", "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "비어 있지 않은 여는 괄호 뒤와 닫는 괄호 앞에 오는 공백 처리를 정의합니다.", - "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "템플릿 문자열의 여는 중괄호 뒤와 닫는 중괄호 앞의 공백 처리를 정의합니다. TypeScript 2.0.6 이상이 필요합니다.", + "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "템플릿 문자열의 여는 중괄호 뒤와 닫는 중괄호 앞의 공백 처리를 정의합니다. TypeScript >= 2.0.6이 필요합니다.", "format.insertSpaceAfterSemicolonInForStatements": " for 문에서 세미콜론 뒤에 오는 공백 처리를 정의합니다.", "format.insertSpaceBeforeAndAfterBinaryOperators": "이항 연산자 뒤에 오는 공백 처리를 정의합니다.", "format.placeOpenBraceOnNewLineForControlBlocks": "제어 블록의 새 줄에 여는 중괄호를 넣을지 정의합니다.", "format.placeOpenBraceOnNewLineForFunctions": "함수의 새 줄에 여는 중괄호를 넣을지 정의합니다.", + "javascript.format.enable": "기본 JavaScript 포맷터를 사용하거나 사용하지 않습니다.", "javascript.reloadProjects.title": "JavaScript 프로젝트 다시 로드", - "javascript.validate.enable": "JavaScript 유효성 검사 사용/사용 안 함", + "javascript.validate.enable": "JavaScript 유효성 검사를 사용하거나 사용하지 않습니다.", "typescript.check.tscVersion": "전역 설치 TypeScript 컴파일러(예: tsc)가 사용된 TypeScript 언어 서비스와 다른지 확인하세요.", "typescript.check.workspaceVersion": "TypeScript 버전을 작업 영역에서 사용할 수 있는지 확인하세요.", - "typescript.experimentalAutomaticTypeAcquisition": "자동 형식 인식을 사용하도록 설정합니다. TypeScript 2.0.6 이상이 필요하며 변경 후 다시 시작해야 합니다.", + "typescript.disableAutomaticTypeAcquisition": "자동 형식 인식을 사용하지 않습니다. TypeScript >= 2.0.6이 필요하며 변경 후 다시 시작해야 합니다.", + "typescript.format.enable": "기본 TypeScript 포맷터를 사용하거나 사용하지 않습니다.", "typescript.reloadProjects.title": "TypeScript 프로젝트 다시 로드", "typescript.tsdk.desc": "사용할 tsserver 및 lib*.d.ts 파일이 들어 있는 폴더 경로를 지정합니다.", "typescript.tsdk_version.desc": "tsserver의 버전을 지정합니다. tsserver가 npm을 사용하여 설치되지 않은 경우에만 필요합니다.", "typescript.tsserver.experimentalAutoBuild": "실험적 자동 빌드를 사용하도록 설정합니다. 1.9 dev 또는 2.x tsserver 버전이 필요하며 변경 후에는 VS Code를 다시 시작해야 합니다.", "typescript.tsserver.trace": "TS 서버에 보내는 메시지를 추적하도록 설정합니다.", "typescript.useCodeSnippetsOnMethodSuggest.dec": "매개 변수 서명으로 함수를 완료하세요.", - "typescript.validate.enable": "TypeScript 유효성 검사 사용/사용 안 함" + "typescript.validate.enable": "TypeScript 유효성 검사를 사용하거나 사용하지 않습니다." } \ No newline at end of file diff --git a/i18n/kor/src/vs/code/electron-main/menus.i18n.json b/i18n/kor/src/vs/code/electron-main/menus.i18n.json index 11d4df82f51..4b964156d1b 100644 --- a/i18n/kor/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/kor/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "끝내기(&&X)", "miFind": "찾기(&&F)", "miFindInFiles": "파일에서 찾기(&&I)", - "miFocusFirstGroup": "왼쪽 그룹(&&L)", - "miFocusSecondGroup": "센터 그룹(&&C)", - "miFocusThirdGroup": "오른쪽 그룹(&&R)", + "miFocusFirstGroup": "첫 번째 그룹(&&F)", + "miFocusSecondGroup": "두 번째 그룹(&&S)", + "miFocusThirdGroup": "세 번째 그룹(&&T)", "miForward": "앞으로(&&F)", "miGotoDefinition": "정의로 이동(&&D)", "miGotoFile": "파일로 이동(&&F)...", "miGotoLine": "줄로 이동(&&L)...", "miGotoSymbolInFile": "파일의 기호로 이동(&&S)...", "miGotoSymbolInWorkspace": "작업 영역의 기호로 이동(&&W)...", + "miHideStatusbar": "상태 표시줄 숨기기(&&H)", "miInstallingUpdate": "업데이트를 설치하는 중...", - "miLicense": "라이선스 보기(&&V)", + "miIntroductoryVideos": "소개 비디오(&&V)", + "miKeyboardShortcuts": "바로 가기 키 참조(&&K)", + "miLicense": "라이선스 보기(&&L)", "miMarker": "문제(&&P)", - "miMoveSidebar": "사이드바 이동(&&M)", + "miMoveSidebarLeft": "사이드바를 왼쪽으로 이동(&&M)", + "miMoveSidebarRight": "사이드바를 오른쪽으로 이동(&&M)", "miNewFile": "새 파일(&&N)", "miNewWindow": "새 창(&&N)", "miNextEditor": "다음 편집기(&&N)", @@ -84,11 +88,13 @@ "miSelectAll": "모두 선택(&&S)", "miSelectColorTheme": "색 테마(&&C)", "miSelectIconTheme": "파일 아이콘 테마(&&I)", + "miShowStatusbar": "상태 표시줄 표시(&&S)", "miSplitEditor": "편집기 분할(&&E)", "miSwitchEditor": "편집기 전환(&&E)", "miSwitchGroup": "그룹 전환(&&G)", "miToggleDebugConsole": "디버그 콘솔(&&B)", "miToggleDevTools": "개발자 도구 설정/해제(&&T)", + "miToggleEditorLayout": "편집기 그룹 레이아웃 설정/해제(&&L)", "miToggleFullScreen": "전체 화면 설정/해제(&&F)", "miToggleIntegratedTerminal": "통합 터미널(&&I)", "miToggleMenuBar": "메뉴 모음 설정/해제(&&B)", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "제어 문자 설정/해제(&&C)", "miToggleRenderWhitespace": "공백 설정/해제 및 렌더링(&&R)", "miToggleSidebar": "사이드바 설정/해제(&&T)", - "miToggleStatusbar": "상태 표시줄 설정/해제(&&T)", "miToggleWordWrap": "자동 줄 바꿈 설정/해제(&&W)", "miTwitter": "Twitter에서 참여(&&J)", "miUndo": "실행 취소(&&U)", diff --git a/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json index 168dde02a5e..0aafa8f647a 100644 --- a/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/kor/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "커서 스타일을 제어합니다. 허용되는 값은 '블록', '줄' 및 '밑줄'입니다.", "detectIndentation": "파일을 열면 파일 콘텐츠를 기반으로 하여 'editor.tabSize'와 'editor.insertSpaces'가 검색됩니다.", "editorConfigurationTitle": "편집기", + "emptySelectionClipboard": "선택 영역 없이 현재 줄 복사 여부를 제어합니다.", "folding": "편집기에서 코드 접기를 사용할지 여부를 제어합니다.", "fontFamily": "글꼴 패밀리를 제어합니다.", "fontLigatures": "글꼴 합자 사용", @@ -23,7 +24,7 @@ "insertSpaces": " 키를 누를 때 공백을 삽입합니다. `editor.detectIndentation`이 켜져 있는 경우 이 설정은 파일 콘텐츠에 따라 재정의됩니다.", "insertSpaces.errorMessage": "'boolean'이 필요합니다. 값 \"auto\"는 `editor.detectIndentation` 설정에 의해 바뀌었습니다.", "lineHeight": "줄 높이를 제어합니다. fontSize의 lineHeight를 계산하려면 0을 사용합니다.", - "lineNumbers": "줄 번호의 표시 여부를 제어합니다.", + "lineNumbers": "줄 번호의 표시 여부를 제어합니다. 가능한 값은 'on', 'off', 'relative'입니다. 'relative'는 현재 커서 위치에서 줄 수를 표시합니다.", "mouseWheelScrollSensitivity": "마우스 휠 스크롤 이벤트의 `deltaX` 및 `deltaY`에서 사용할 승수", "mouseWheelZoom": "마우스 휠을 사용할 때 Ctrl 키를 누르고 있으면 편집기의 글꼴 확대/축소", "overviewRulerLanes": "개요 눈금자에서 동일한 위치에 표시될 수 있는 장식 수를 제어합니다.", diff --git a/i18n/kor/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/kor/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index 35724c7bae0..704c0ead84c 100644 --- a/i18n/kor/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "접근성 도움말 표시", - "introMsg": "VS Code의 실험적 접근성 옵션을 사용해 주셔서 감사합니다.", + "introMsg": "VS Code의 접근성 옵션을 사용해 주셔서 감사합니다.", "outroMsg": "이 도구 설명을 해제하고 Esc 키를 눌러서 편집기로 돌아갈 수 있습니다.", "status": "상태:", - "tabFocusModeOffMsg": "이 편집기에서 Tab 키를 누르면 탬 문자가 삽입됩니다. {0}을(를) 눌러서 이 동작을 설정/해제합니다.", - "tabFocusModeOffMsgNoKb": "이 편집기에서 Tab 키를 누르면 포커스가 다음 포커스 가능한 요소로 이동합니다. {0} 명령은 현재 키 바인딩으로 트리거할 수 없습니다.", - "tabFocusModeOnMsg": "이 편집기에서 Tab 키를 누르면 포커스가 다음 포커스 가능한 요소로 이동합니다. {0}을(를) 눌러서 이 동작을 설정/해제합니다.", - "tabFocusModeOnMsgNoKb": "이 편집기에서 Tab 키를 누르면 포커스가 다음 포커스 가능한 요소로 이동합니다. {0} 명령은 현재 키 바인딩으로 트리거할 수 없습니다." + "tabFocusModeOffMsg": "현재 편집기에서 키를 누르면 탭 문자가 삽입됩니다. {0}을(를) 눌러서 이 동작을 설정/해제합니다.", + "tabFocusModeOffMsgNoKb": "현재 편집기에서 키를 누르면 탭 문자가 삽입됩니다. {0} 명령은 현재 키 바인딩으로 트리거할 수 없습니다.", + "tabFocusModeOnMsg": "현재 편집기에서 키를 누르면 포커스가 다음 포커스 가능한 요소로 이동합니다. {0}을(를) 눌러서 이 동작을 설정/해제합니다.", + "tabFocusModeOnMsgNoKb": "현재 편집기에서 키를 누르면 포커스가 다음 포커스 가능한 요소로 이동합니다. {0} 명령은 현재 키 바인딩으로 트리거할 수 없습니다." } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/kor/src/vs/editor/contrib/format/common/formatActions.i18n.json index 78d0b5607ca..291f41fad64 100644 --- a/i18n/kor/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/kor/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "코드 서식" + "formatDocument.label": "문서 서식", + "formatSelection.label": "선택 영역 서식" } \ No newline at end of file diff --git a/i18n/kor/src/vs/editor/node/textMate/TMSyntax.i18n.json b/i18n/kor/src/vs/editor/node/textMate/TMSyntax.i18n.json index 990bcc3a590..408d6a1a1f1 100644 --- a/i18n/kor/src/vs/editor/node/textMate/TMSyntax.i18n.json +++ b/i18n/kor/src/vs/editor/node/textMate/TMSyntax.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.embeddedLanguages": "`contributes.{0}.embeddedLanguages`의 잘못된 값입니다. 범위 이름에서 언어까지의 개체 맵이어야 합니다. 제공된 값: {1}", "invalid.injectTo": "`contributes.{0}.injectTo`의 값이 잘못되었습니다. 언어 범위 이름 배열이어야 합니다. 제공된 값: {1}", "invalid.language": "`contributes.{0}.language`에 알 수 없는 언어가 있습니다. 제공된 값: {1}", "invalid.path.0": "`contributes.{0}.path`에 문자열이 필요합니다. 제공된 값: {1}", "invalid.path.1": "확장 폴더({2})에 포함할 `contributes.{0}.path`({1})가 필요합니다. 확장이 이식 불가능해질 수 있습니다.", "invalid.scopeName": "`contributes.{0}.scopeName`에 문자열이 필요합니다. 제공된 값: {1}", "vscode.extension.contributes.grammars": "textmate 토크나이저를 적용합니다.", + "vscode.extension.contributes.grammars.embeddedLanguages": "이 문법에 포함된 언어가 있는 경우 언어 ID에 대한 범위 이름의 맵입니다.", "vscode.extension.contributes.grammars.injectTo": "이 문법이 삽입되는 언어 범위 이름 목록입니다.", "vscode.extension.contributes.grammars.language": "이 구문이 적용되는 언어 식별자입니다.", "vscode.extension.contributes.grammars.path": "tmLanguage 파일의 경로입니다. 이 경로는 확장 폴더에 상대적이며 일반적으로 './syntaxes/'로 시작합니다.", diff --git a/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index edfb1f9f4da..5426b9f5587 100644 --- a/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/kor/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "취소", "doNotInstall": "아니요", "install": "예", "installDependeciesConfirmation": "'{0}'을(를) 설치하면 종속성도 설치됩니다. 계속할까요?", @@ -11,6 +12,14 @@ "invalidName": "잘못된 확장: 매니페스트 이름이 일치하지 않습니다.", "invalidPublisher": "잘못된 확장: 매니페스트 게시자가 일치하지 않습니다.", "invalidVersion": "잘못된 확장: 매니페스트 버전이 일치하지 않습니다.", + "multipleDependentsError": "확장 '{0}'을(를) 제거할 수 없습니다. 확장 '{1}', '{2}' 등이 이 확장에 종속됩니다.", "notExists": "확장을 찾을 수 없음", - "restartCode": "{0}을(를) 다시 설치하기 전에 Code를 다시 시작하세요." + "ok": "확인", + "restartCode": "{0}을(를) 다시 설치하기 전에 Code를 다시 시작하세요.", + "singleDependentError": "확장 '{0}'을(를) 제거할 수 없습니다. 확장 '{1}'이(가) 이 확장에 종속됩니다.", + "twoDependentsError": "확장 '{0}'을(를) 제거할 수 없습니다. 확장 '{1}' 및 '{2}'이(가) 이 확장에 종속됩니다.", + "uninstallAll": "모두", + "uninstallConfirmation": "'{0}'을(를) 제거할까요?", + "uninstallDependeciesConfirmation": "'{0}'만 제거할까요, 아니면 종속성도 제거할까요?", + "uninstallOnly": "만" } \ No newline at end of file diff --git a/i18n/kor/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/kor/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 660a9006bea..007a431f53c 100644 --- a/i18n/kor/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/kor/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "속성 `{0}`은(는) 생략할 수 있으며 `string[]` 형식이어야 합니다.", - "extensionDescription.activationEvents2": "속성 `{0}` 및 `{1}`은(는) 둘 다 지정하거나 둘 다 생략해야 합니다.", - "extensionDescription.empty": "가져온 확장 설명이 비어 있습니다.", - "extensionDescription.engines": "속성 `{0}`은(는) 필수이며 `object` 형식이어야 합니다.", - "extensionDescription.engines.vscode": "속성 `{0}`은(는) 필수이며 `string` 형식이어야 합니다.", - "extensionDescription.extensionDependencies": "속성 `{0}`은(는) 생략할 수 있으며 `string[]` 형식이어야 합니다.", - "extensionDescription.main1": "속성 `{0}`은(는) 생략할 수 있으며 `string` 형식이어야 합니다.", - "extensionDescription.main2": "확장의 폴더({1}) 내에 포함할 `main`({0})이 필요합니다. 이로 인해 확장이 이식 불가능한 상태가 될 수 있습니다.", - "extensionDescription.main3": "속성 `{0}` 및 `{1}`은(는) 둘 다 지정하거나 둘 다 생략해야 합니다.", - "extensionDescription.name": "속성 `{0}`은(는) 필수이며 `string` 형식이어야 합니다.", - "extensionDescription.publisher": "속성 `{0}`은(는) 필수이며 `string` 형식이어야 합니다.", - "extensionDescription.version": "속성 `{0}`은(는) 필수이며 `string` 형식이어야 합니다.", "vscode.extension.activationEvents": "VS Code 확장에 대한 활성화 이벤트입니다.", "vscode.extension.badges": "마켓플레이스 확장 페이지의 사이드바에 표시할 배지의 배열입니다.", "vscode.extension.badges.description": "배지 설명입니다.", @@ -24,6 +12,7 @@ "vscode.extension.categories": "확장을 분류하기 위해 VS Code 갤러리에서 사용하는 범주입니다.", "vscode.extension.contributes": "이 패키지에 표시된 VS Code 확장의 전체 기여입니다.", "vscode.extension.displayName": "VS Code 갤러리에 사용되는 확장의 표시 이름입니다.", + "vscode.extension.engines.vscode": "VS Code 확장의 경우, 확장이 호환되는 VS Code 버전을 지정합니다. *일 수 없습니다. 예를 들어 ^0.10.5는 최소 VS Code 버전인 0.10.5와 호환됨을 나타냅니다.", "vscode.extension.extensionDependencies": "다른 확장에 대한 종속성입니다. 확장 식별자는 항상 ${publisher}.${name}입니다(예: vscode.csharp).", "vscode.extension.galleryBanner": "VS Code 마켓플레이스에 사용되는 배너입니다.", "vscode.extension.galleryBanner.color": "VS Code 마켓플레이스 페이지 머리글의 배너 색상입니다.", diff --git a/i18n/kor/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/kor/src/vs/workbench/browser/actions/openSettings.i18n.json index 642608b4ef9..5ce168b5751 100644 --- a/i18n/kor/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "기본 바로 가기 키", "defaultKeybindingsHeader": "키 바인딩을 키 바인딩 파일에 배치하여 덮어씁니다.", "defaultName": "기본 설정", + "defaultSettingsEditor": "기본 설정 편집기", "defaultSettingsHeader": "설정을 설정 파일에 배치하여 덮어씁니다.", "defaultSettingsHeader2": "가장 일반적으로 사용되는 설정은 http://go.microsoft.com/fwlink/?LinkId=808995를 참조하세요.", "emptyKeybindingsHeader": "키 바인딩을 이 파일에 넣어서 기본값을 덮어씁니다.", diff --git a/i18n/kor/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/kor/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..45c17eeba5c 100644 --- a/i18n/kor/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "가로 편집기 그룹 레이아웃", + "toggleEditorGroupLayout": "편집기 그룹 세로/가로 레이아웃 설정/해제", + "verticalLayout": "세로 편집기 그룹 레이아웃", + "view": "보기" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 1c165d359ff..5d7115e8267 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "열려 있는 모든 편집기 표시", "binaryDiffEditor": "이진 Diff 편집기", - "centerEditorGroupPicker": "센터 그룹의 편집기 표시", - "leftEditorGroupPicker": "왼쪽 그룹의 편집기 표시", - "rightEditorGroupPicker": "오른쪽 그룹의 편집기 표시", + "groupOnePicker": "첫 번째 그룹에 편집기 표시", + "groupThreePicker": "세 번째 그룹에 편집기 표시", + "groupTwoPicker": "두 번째 그룹에 편집기 표시", "textDiffEditor": "텍스트 Diff 편집기", "textEditor": "텍스트 편집기", "view": "보기" diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 447ecb23a2e..71451b2ac72 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "다른 편집기 닫기", "evenEditorGroups": "균등한 편집기 그룹 너비", "focusActiveEditorGroup": "활성 편집기 그룹에 포커스", - "focusFirstEditorGroup": "왼쪽 편집기 그룹으로 포커스 이동", + "focusFirstEditorGroup": "첫 번째 편집기 그룹으로 포커스 이동", "focusLastEditorInStack": "그룹의 마지막 편집기 열기", "focusNextGroup": "다음 그룹으로 포커스 이동", "focusPreviousGroup": "이전 그룹으로 포커스 이동", - "focusSecondEditorGroup": "센터 편집기 그룹으로 포커스 이동", - "focusThirdEditorGroup": "오른쪽 편집기 그룹으로 포커스 이동", + "focusSecondEditorGroup": "두 번째 편집기 그룹으로 포커스 이동", + "focusThirdEditorGroup": "세 번째 편집기 그룹으로 포커스 이동", "keepEditor": "편집기 유지", "maximizeEditor": "편집기 그룹 최대화 및 사이드바 숨기기", "minimizeOtherEditorGroups": "다른 편집기 그룹 최소화", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "편집기 그룹을 오른쪽으로 이동", "moveEditorLeft": "왼쪽으로 편집기 이동", "moveEditorRight": "오른쪽으로 편집기 이동", - "moveEditorToLeftGroup": "편집기를 왼쪽 그룹으로 이동", - "moveEditorToRightGroup": "편집기를 오른쪽 그룹으로 이동", + "moveEditorToNextGroup": "편집기를 다음 그룹으로 이동", + "moveEditorToPreviousGroup": "편집기를 이전 그룹으로 이동", "navigateEditorGroups": "편집기 그룹 간 탐색", "navigateEditorHistoryByInput": "기록에서 이전 편집기 열기", "navigateNext": "앞으로 이동", @@ -38,12 +38,11 @@ "openPreviousEditor": "이전 편집기 열기", "openPreviousEditorInGroup": "그룹에서 최근에 사용한 이전 편집기 열기", "openToSide": "측면에서 열기", - "removeFromEditorHistory": "편집기 기록에서 제거", "reopenClosedEditor": "닫힌 편집기 다시 열기", "showAllEditors": "모든 편집기 표시", - "showEditorsInCenterGroup": "센터 그룹의 편집기 표시", + "showEditorsInFirstGroup": "첫 번째 그룹에 편집기 표시", "showEditorsInGroup": "그룹의 편집기 표시", - "showEditorsInLeftGroup": "왼쪽 그룹의 편집기 표시", - "showEditorsInRightGroup": "오른쪽 그룹의 편집기 표시", + "showEditorsInSecondGroup": "두 번째 그룹에 편집기 표시", + "showEditorsInThirdGroup": "세 번째 그룹에 편집기 표시", "splitEditor": "편집기 분할" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index 01e5772020a..534a6bf04e5 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "센터", "editorOpenError": "'{0}'을(를) 열 수 없습니다. {1}.", - "leftGroup": "왼쪽", - "rightGroup": "오른쪽" + "groupOneHorizontal": "위쪽", + "groupOneVertical": "왼쪽", + "groupThreeHorizontal": "아래쪽", + "groupThreeVertical": "오른쪽", + "groupTwoHorizontal": "가운데", + "groupTwoVertical": "가운데" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index f0f355ede8f..abe064fbac6 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0}, 편집기 그룹 선택기", "groupLabel": "그룹: {0}", - "noOpenedEditors": "열려 있는 편집기 목록이 현재 비어 있습니다.", + "noOpenedEditors": "열려 있는 편집기 목록이 현재 그룹에서 비어 있습니다.", + "noOpenedEditorsAllGroups": "열려 있는 편집기 목록이 현재 비어 있습니다.", "noResultsFound": "일치하는 열려 있는 편집기를 찾을 수 없습니다.", "noResultsFoundInGroup": "그룹에서 일치하는 열려 있는 편집기를 찾을 수 없습니다." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/kor/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index bbf5075599a..f3c5aa79924 100644 --- a/i18n/kor/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/kor/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "줄 시퀀스의 끝 선택", "selectEncoding": "인코딩 선택", "selectLanguageMode": "언어 모드 선택", + "showLanguageExtensions": "'{0}'의 마켓플레이스 확장 검색...", "singleSelection": "줄 {0}, 열 {1}", "singleSelectionRange": "줄 {0}, 열 {1}({2} 선택됨)", "spacesSize": "공간: {0}", diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index 519f74af648..a0b74f8ee08 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "이 조건이 true인 경우에만 프로그램이 여기서 중지됩니다. 수락하려면 키를 누르고, 취소하려면 키를 누르세요.", - "breakpointWidgetExpressionPlaceholder": "식이 true로 계산될 경우 중단", + "breakpointWidgetExpressionPlaceholder": "식이 true로 계산될 경우 중단합니다. 적용하려면 'Enter' 키를 누르고 취소하려면 'Esc' 키를 누릅니다.", "breakpointWidgetHitCountAriaLabel": "적중 횟수가 충족되는 경우에만 프로그램이 여기서 중지됩니다. 수락하려면 키를 누르고, 취소하려면 키를 누르세요.", - "breakpointWidgetHitCountPlaceholder": "적중 횟수 조건이 충족될 경우 중단", + "breakpointWidgetHitCountPlaceholder": "적중 횟수 조건이 충족될 경우 중단합니다. 적용하려면 'Enter' 키를 누르고 취소하려면 'Esc' 키를 누릅니다.", "expression": "식", "hitCount": "적중 횟수" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index 97e70d80fea..176b7826073 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "디버그: 조건부 중단점 추가...", "continueDebug": "계속", "deactivateBreakpoints": "중단점 비활성화", - "debugActionLabelAndKeybinding": "{0}({1})", "debugAddToWatch": "디버그: 조사식에 추가", "debugConsoleAction": "디버그 콘솔", "debugEvaluate": "디버그: 평가", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "모든 중단점 해제", "disconnectDebug": "연결 끊기", "editConditionalBreakpoint": "중단점 편집...", + "editWatchExpression": "식 편집", "enableAllBreakpoints": "모든 중단점 설정", "launchJsonNeedsConfigurtion": "'launch.json' 구성 또는 수정", "openLaunchJson": "{0} 열기", @@ -32,7 +32,6 @@ "removeBreakpoint": "중단점 제거", "removeWatchExpression": "식 제거", "renameFunctionBreakpoint": "함수 중단점 이름 바꾸기", - "renameWatchExpression": "식 이름 바꾸기", "restartDebug": "다시 시작", "restartFrame": "프레임 다시 시작", "runToCursor": "디버그: 커서까지 실행", diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index c92508b7198..81dc8c302d4 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,13 +4,12 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "확장명에 관계없이 모든 파일에 대한 중단점을 설정할 수 있습니다.", + "allowBreakpointsEverywhere": "모든 파일에 대한 중단점을 설정할 수 있습니다.", "debug": "디버그", "debugCategory": "디버그", "debugConfigurationTitle": "디버그", "debugErrorEditor": "디버그 오류", "debugPanel": "디버그 콘솔", - "launchConfigDoesNotExist": "시작 구성 '{0}'이(가) 없습니다.", "openExplorerOnEnd": "디버그 세션 끝에 탐색기 뷰렛을 자동으로 엽니다.", "toggleDebugPanel": "디버그 콘솔", "toggleDebugViewlet": "디버그 표시", diff --git a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json index 0783c1c52ac..2dd9167f100 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json @@ -12,6 +12,7 @@ "functionBreakpointsNotSupported": "이 디버그 형식은 함수 중단점을 지원하지 않습니다.", "loadMoreStackFrames": "더 많은 스택 프레임 로드", "paused": "일시 중지됨", + "process": "프로세스", "running": "실행 중", "stackFrameAriaLabel": "스택 프레임 {0} 줄 {1} {2}, 호출 스택, 디버그", "thread": "스레드", diff --git a/i18n/kor/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/kor/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 05168f93b8d..0438976a903 100644 --- a/i18n/kor/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "debugConfigurationNames": "이 \"복합\" 구성의 일부로 실행될 구성입니다. 이 구성의 형식이 \"복합\"인 경우에만 적용됩니다.", "debugLinuxConfiguration": "Linux 특정 시작 구성 특성입니다.", "debugName": "구성 이름이며, 구성 시작 드롭다운 메뉴에 표시됩니다.", "debugOSXConfiguration": "OS X 특정 시작 구성 특성입니다.", diff --git a/i18n/kor/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/kor/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 33d5f7f1ebd..30ceadac5db 100644 --- a/i18n/kor/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "권장 사항은 작업 영역 폴더에서만 사용할 수 있습니다.", "OpenExtensionsFile.failed": "'.vscode' 폴더 내에 'extensions.json' 파일을 만들 수 없습니다({0}).", - "OpenGlobalExtensionsStorageFile.failed": "'{0}' 폴더 내에 'extensions.json' 파일을 만들 수 없습니다({1}).", + "Uninstalling": "제거하는 중", "builtin": "기본 제공", "clearExtensionsInput": "확장 입력 지우기", "configureWorkspaceRecommendedExtensions": "권장 확장 구성(작업 영역)", - "deleteSure": "'{0}'을(를) 제거할까요?", + "disableAction": "사용 안 함", + "disableAll": "모두 사용 안 함", + "disableAllWorkspace": "모두 사용 안 함(작업 영역)", + "disableAlwaysAction.label": "사용 안 함", + "disableForWorkspaceAction": "작업 영역", + "disableForWorkspaceAction.label": "사용 안 함(작업 영역)", + "disableGloballyAction": "항상", "enableAction": "사용", + "enableAll": "모두 사용", + "enableAllWorkspace": "모두 사용(작업 영역)", + "enableAlwaysAction.label": "사용", + "enableForWorkspaceAction": "작업 영역", + "enableForWorkspaceAction.label": "사용(작업 영역)", + "enableGloballyAction": "항상", "installAction": "설치", "installExtensions": "확장 설치", "installVSIX": "VSIX에서 설치...", "installing": "설치 중", "openExtensionsFolder": "Extensions 폴더 열기", - "postUninstallMessage": "'{0}'이(가) 제거되었습니다. 비활성화하려면 다시 시작하세요.", - "restart": "이 확장을 사용하도록 설정하려면 이 VS Code 창을 다시 시작해야 합니다.\n\n계속할까요?", - "restartNow": "지금 다시 시작", + "postDisableMessage": "'{0}' 확장을 사용하지 않도록 이 창을 다시 로드할까요?", + "postDisableTooltip": "사용하지 않으려면 다시 로드", + "postEnableMessage": "'{0}' 확장을 사용하도록 이 창을 다시 로드할까요?", + "postEnableTooltip": "사용하도록 다시 로드", + "postInstallMessage": "'{0}' 확장을 활성화하도록 이 창을 다시 로드할까요?", + "postInstallTooltip": "활성화하려면 다시 로드", + "postUninstallMessage": "'{0}' 확장을 비활성화하도록 이 창을 다시 로드할까요?", + "postUninstallTooltip": "비활성화하려면 다시 로드", + "reloadAction": "다시 로드", + "reloadNow": "지금 다시 로드", "showDisabledExtensions": "사용할 수 없는 확장 표시", "showInstalledExtensions": "설치된 확장 표시", "showOutdatedExtensions": "만료된 확장 표시", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "권장되는 확장 표시", "showWorkspaceRecommendedExtensions": "작업 영역 권장 확장 표시", "toggleExtensionsViewlet": "확장 표시", - "uninstall": "제거", + "uninstallAction": "제거", "updateAction": "업데이트", "updateAll": "모든 확장 업데이트" } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/kor/src/vs/workbench/parts/git/node/git.lib.i18n.json index d48fe3d053e..3845e66fd4a 100644 --- a/i18n/kor/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "git에서 파일을 열 수 없습니다.", "fileBinaryError": "파일이 이진인 것 같으므로 테스트로 열 수 없습니다." } \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/html/browser/webview.i18n.json b/i18n/kor/src/vs/workbench/parts/html/browser/webview.i18n.json index 8b6ad71cd4e..fc0ecfdc6c7 100644 --- a/i18n/kor/src/vs/workbench/parts/html/browser/webview.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/html/browser/webview.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "devtools.webview": "개발자: Webview 도구" +} \ No newline at end of file diff --git a/i18n/kor/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/kor/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index a794556318c..81fdd85b182 100644 --- a/i18n/kor/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "첫 번째 텍스트 파일을 열어서 줄로 이동합니다.", "gotoLine": "줄 이동...", - "gotoLineColumnLabel": "줄 {0} 및 열 {1}(으)로 이동", + "gotoLineColumnLabel": "줄 {0} 및 문자 {1}(으)로 이동", "gotoLineHandlerAriaLabel": "이동할 줄 번호를 입력합니다.", "gotoLineLabel": "줄 {0}(으)로 이동", "gotoLineLabelEmpty": "이동할 줄 번호 입력", diff --git a/i18n/kor/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/kor/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 05d4842aec1..161e78b02d2 100644 --- a/i18n/kor/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/kor/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "지금 다운로드", + "insiderBuilds": "참가자 빌드가 매일 릴리스됩니다.", "later": "나중에", + "license": "라이선스 읽기", + "licenseChanged": "사용 조건이 변경되었습니다. 자세히 읽어보세요.", + "neverShowAgain": "다시 표시 안 함", "noUpdatesAvailable": "현재 사용 가능한 업데이트가 없습니다.", "read the release notes": "{0} v{1}을(를) 시작합니다. 릴리스 정보를 확인하시겠습니까?", + "readmore": "자세히 알아보기", "releaseNotes": "릴리스 정보", "showReleaseNotes": "릴리스 정보 표시", "thereIsUpdateAvailable": "사용 가능한 업데이트가 있습니다.", diff --git a/i18n/rus/extensions/typescript/out/features/bufferSyncSupport.i18n.json b/i18n/rus/extensions/typescript/out/features/bufferSyncSupport.i18n.json index 8c6ad54ecbe..b44b05dca83 100644 --- a/i18n/rus/extensions/typescript/out/features/bufferSyncSupport.i18n.json +++ b/i18n/rus/extensions/typescript/out/features/bufferSyncSupport.i18n.json @@ -4,5 +4,9 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "close": "Закрыть", + "doNotCheckAgain": "Больше не проверять", + "moreInformation": "Дополнительные сведения", + "updateTscCheck": "Значение параметра пользователя \"typescript.check.tscVersion\" изменено на false.", "versionMismatch": "Обнаружено несоответствие глобального tsc ({0}) и службы языка VS Code ({1}). Это может привести к ошибкам согласованности компиляции." } \ No newline at end of file diff --git a/i18n/rus/extensions/typescript/package.i18n.json b/i18n/rus/extensions/typescript/package.i18n.json index 0289fe7a66a..0fee41d0ec2 100644 --- a/i18n/rus/extensions/typescript/package.i18n.json +++ b/i18n/rus/extensions/typescript/package.i18n.json @@ -4,28 +4,30 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "configuration.typescript": "TypeScript", - "format.insertSpaceAfterCommaDelimiter": "Определяет метод обработки пробелов после разделителя-запятой", - "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Определяет метод обработки пробелов после ключевого слова анонимной функции", - "format.insertSpaceAfterKeywordsInControlFlowStatements": "Определяет метод обработки пробелов после ключевых слов в операторе потока управления", + "configuration.typescript": "TypeScript.", + "format.insertSpaceAfterCommaDelimiter": "Определяет метод обработки пробелов после разделителя-запятой.", + "format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": "Определяет метод обработки пробелов после ключевого слова function у анонимных функций.", + "format.insertSpaceAfterKeywordsInControlFlowStatements": "Определяет метод обработки пробелов после ключевых слов в операторе управления потоком выполнения.", "format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": "Определяет метод обработки пробелов после открытия и до закрытия скобок выражения JSX. Требуется TypeScript 2.0.6 или более поздней версии.", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Определяет метод обработки пробелов после открытия и до закрытия непустых квадратных скобок", - "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Определяет метод обработки пробелов после открытия и до закрытия непустых круглых скобок", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": "Определяет метод обработки пробелов после открытия и до закрытия непустых квадратных скобок.", + "format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": "Определяет метод обработки пробелов после открытия и до закрытия непустых круглых скобок.", "format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": "Определяет метод обработки пробелов после открытия и до закрытия скобок в строке шаблона. Требуется TypeScript 2.0.6 или более поздней версии.", - "format.insertSpaceAfterSemicolonInForStatements": " Определяет метод обработки пробелов после точки с запятой в операторе for", - "format.insertSpaceBeforeAndAfterBinaryOperators": "Определяет метод обработки пробелов после двоичного оператора", - "format.placeOpenBraceOnNewLineForControlBlocks": "Определяет, помещается ли открывающая фигурная скобка в новую строку для управляющих блоков", - "format.placeOpenBraceOnNewLineForFunctions": "Определяет, помещается ли открывающая фигурная скобка в новую строку для функций", + "format.insertSpaceAfterSemicolonInForStatements": " Определяет метод обработки пробелов после точки с запятой в операторе for.", + "format.insertSpaceBeforeAndAfterBinaryOperators": "Определяет метод обработки пробелов после двоичного оператора.", + "format.placeOpenBraceOnNewLineForControlBlocks": "Определяет, ставится ли открывающая фигурная скобка с новой строки в блоках управления.", + "format.placeOpenBraceOnNewLineForFunctions": "Определяет, ставится ли открывающая фигурная скобка с новой строки в функциях.", + "javascript.format.enable": "Включение или отключение модуля форматирования JavaScript по умолчанию.", "javascript.reloadProjects.title": "Перезагрузка проекта JavaScript", - "javascript.validate.enable": "Включить или отключить проверку JavaScript", + "javascript.validate.enable": "Включение или отключение проверки JavaScript.", "typescript.check.tscVersion": "Проверка отличия компилятора TypeScript глобальной установки (например, tsc) от используемой языковой службы TypeScript.", - "typescript.check.workspaceVersion": "Проверка наличия версии TypeScript в рабочей области", - "typescript.experimentalAutomaticTypeAcquisition": "Включить автоматическое получение типа. Требуется TypeScript 2.0.6 или более поздней версии и перезапуск после внесения изменений.", + "typescript.check.workspaceVersion": "Проверка наличия версии TypeScript в рабочей области.", + "typescript.disableAutomaticTypeAcquisition": "Отключает автоматическое получение типа. Требуется TypeScript 2.0.6 и более поздней версии и перезапуск после его изменения.", + "typescript.format.enable": "Включение или отключение модуля форматирования TypeScript по умолчанию.", "typescript.reloadProjects.title": "Перезагрузка проекта TypeScript", "typescript.tsdk.desc": "Указывает путь к папке, содержащей файлы tsserver и lib*.d.ts, которые необходимо использовать.", "typescript.tsdk_version.desc": "Указывает версию tsserver. Требуется, только если tsserver не установлен с помощью npm.", "typescript.tsserver.experimentalAutoBuild": "Включает экспериментальную автосборку. Требуется версия 1.9 dev или версия 2.x tsserver и перезапуск VS Code после изменения.", - "typescript.tsserver.trace": "Включение трассировки сообщений, отправленных на сервер TS", + "typescript.tsserver.trace": "Включение трассировки сообщений, отправленных на сервер TS.", "typescript.useCodeSnippetsOnMethodSuggest.dec": "Дополните функции сигнатурами их параметров.", - "typescript.validate.enable": "Включить или отключить проверку TypeScript" + "typescript.validate.enable": "Включение или отключение проверки TypeScript." } \ No newline at end of file diff --git a/i18n/rus/src/vs/code/electron-main/menus.i18n.json b/i18n/rus/src/vs/code/electron-main/menus.i18n.json index 467e5d99a03..eb2484e7f0f 100644 --- a/i18n/rus/src/vs/code/electron-main/menus.i18n.json +++ b/i18n/rus/src/vs/code/electron-main/menus.i18n.json @@ -37,19 +37,23 @@ "miExit": "В&&ыход", "miFind": "&&Найти", "miFindInFiles": "Найти в &&файлах", - "miFocusFirstGroup": "&&Левая группа", - "miFocusSecondGroup": "&&Центральная группа", - "miFocusThirdGroup": "&&Правая группа", + "miFocusFirstGroup": "&&Первая группа", + "miFocusSecondGroup": "&&Вторая группа", + "miFocusThirdGroup": "&&Третья группа", "miForward": "&&Вперед", "miGotoDefinition": "Перейти к &&определению", "miGotoFile": "Перейти к &&файлу...", "miGotoLine": "Перейти к &&строке...", "miGotoSymbolInFile": "Перейти к &&символу в файле...", "miGotoSymbolInWorkspace": "Перейти к символу в &&рабочей области...", + "miHideStatusbar": "&&Скрыть строку состояния", "miInstallingUpdate": "Идет установка обновления...", - "miLicense": "&&Просмотреть лицензию", + "miIntroductoryVideos": "Вступительные в&&идео", + "miKeyboardShortcuts": "С&&правочник по сочетаниям клавиш", + "miLicense": "Просмотреть &&лицензию", "miMarker": "&&Проблемы", - "miMoveSidebar": "&&Переместить боковую панель", + "miMoveSidebarLeft": "&&Переместить боковую панель влево", + "miMoveSidebarRight": "&&Переместить боковую панель вправо", "miNewFile": "&&Новый файл", "miNewWindow": "&&Новое окно", "miNextEditor": "&&Следующий редактор", @@ -84,11 +88,13 @@ "miSelectAll": "&&Выделить все", "miSelectColorTheme": "Цветовая &&тема", "miSelectIconTheme": "Тема значка &&файла", + "miShowStatusbar": "&&Показать строку состояния", "miSplitEditor": "Разделить &&редактор", "miSwitchEditor": "Переключить р&&едактор", "miSwitchGroup": "Переключить &&группу", "miToggleDebugConsole": "Ко&&нсоль отладки", "miToggleDevTools": "&&Показать/скрыть средства разработчика", + "miToggleEditorLayout": "Переключить &&структуру группы редакторов", "miToggleFullScreen": "Включить/выключить полно&&экранный режим", "miToggleIntegratedTerminal": "&&Интегрированный терминал", "miToggleMenuBar": "Показать/скрыть строку &&меню", @@ -97,7 +103,6 @@ "miToggleRenderControlCharacters": "Переключить &&управляющие символы", "miToggleRenderWhitespace": "Показать/&&скрыть символы пробелов", "miToggleSidebar": "Показать/скрыть &&боковую панель", - "miToggleStatusbar": "&&Переключить строку состояния", "miToggleWordWrap": "&&Включить/выключить перенос текста", "miTwitter": "&&Присоединяйтесь к нам в Twitter", "miUndo": "&&Отменить", diff --git a/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json b/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json index 3142a472988..84599107a73 100644 --- a/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json +++ b/i18n/rus/src/vs/editor/common/config/commonEditorConfig.i18n.json @@ -11,6 +11,7 @@ "cursorStyle": "Определяет стиль курсора. Допустимые значения: \"block\", \"line\" и \"underline\"", "detectIndentation": "При открытии файла editor.tabSize и editor.insertSpaces будут определяться на основе содержимого файла.", "editorConfigurationTitle": "Редактор", + "emptySelectionClipboard": "Управляет тем, копируется ли текущая строка при копировании без выделения.", "folding": "Определяет, включено ли сворачивание кода в редакторе.", "fontFamily": "Определяет семейство шрифтов.", "fontLigatures": "Включает лигатуры шрифта.", @@ -23,7 +24,7 @@ "insertSpaces": "Вставлять пробелы при нажатии клавиши TAB. Эта настройка переопределяется на основании содержимого файла, когда включен параметр \"editor.detectIndentation\".", "insertSpaces.errorMessage": "Ожидается логическое значение. Обратите внимание, что значение auto заменено параметром editor.detectIndentation.", "lineHeight": "Управляет высотой строк. Укажите 0 для вычисления высоты строки по размеру шрифта.", - "lineNumbers": "Управляет видимостью номеров строк.", + "lineNumbers": "Управляет видимостью номеров строк. Возможные значения: \"on\", \"off\" и \"relative\". Значение \"relative\" показывает количество строк, начиная с текущего положения курсора.", "mouseWheelScrollSensitivity": "Множитель, используемый для параметров deltaX и deltaY событий прокрутки колесика мыши.", "mouseWheelZoom": "Изменение размера шрифта в редакторе при нажатой клавише CTRL и движении колесика мыши", "overviewRulerLanes": "Определяет, сколько украшений могут отображаться на одном месте в обзорной линейке.", diff --git a/i18n/rus/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json b/i18n/rus/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json index 639ae59de5a..0b3cff6596b 100644 --- a/i18n/rus/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/accessibility/browser/accessibility.i18n.json @@ -5,11 +5,11 @@ // Do not edit this file. It is machine generated. { "ShowAccessibilityHelpAction": "Показать справку по специальным возможностям", - "introMsg": "Благодарим за ознакомление с экспериментальными специальными возможностями VS Code.", + "introMsg": "Благодарим за ознакомление со специальными возможностями VS Code.", "outroMsg": "Вы можете закрыть эту подсказку и вернуться в редактор, нажав клавишу ESCAPE.", "status": "Состояние:", - "tabFocusModeOffMsg": "При нажатии клавиши TAB в этом редакторе будет вставлен символ табуляции. Чтобы изменить это поведение, нажмите клавишу {0}.", - "tabFocusModeOffMsgNoKb": "При нажатии клавиши TAB в этом редакторе фокус ввода переместится на следующий элемент, допускающий получение фокуса ввода. Команду {0} в настоящее время нельзя выполнить с помощью настраиваемого сочетания клавиш.", - "tabFocusModeOnMsg": "При нажатии клавиши TAB в этом редакторе фокус ввода переместится на следующий элемент, допускающий получение фокуса ввода. Чтобы изменить это поведение, нажмите клавишу {0}.", - "tabFocusModeOnMsgNoKb": "При нажатии клавиши TAB в этом редакторе фокус ввода переместится на следующий элемент, допускающий получение фокуса ввода. Команду {0} в настоящее время нельзя выполнить с помощью настраиваемого сочетания клавиш." + "tabFocusModeOffMsg": "При нажатии клавиши TAB в текущем редакторе будет вставлен символ табуляции. Чтобы изменить это поведение, нажмите клавишу {0}.", + "tabFocusModeOffMsgNoKb": "При нажатии клавиши TAB в текущем редакторе будет вставлен символ табуляции. Команду {0} сейчас невозможно выполнить с помощью настраиваемого сочетания клавиш.", + "tabFocusModeOnMsg": "При нажатии клавиши TAB в текущем редакторе фокус ввода переместится на следующий элемент, способный его принять. Чтобы изменить это поведение, нажмите клавишу {0}.", + "tabFocusModeOnMsgNoKb": "При нажатии клавиши TAB в текущем редакторе фокус ввода переместится на следующий элемент, способный его принять. Команду {0} сейчас невозможно выполнить с помощью настраиваемого сочетания клавиш." } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/contrib/format/common/formatActions.i18n.json b/i18n/rus/src/vs/editor/contrib/format/common/formatActions.i18n.json index f2c888183e5..27244f6f01b 100644 --- a/i18n/rus/src/vs/editor/contrib/format/common/formatActions.i18n.json +++ b/i18n/rus/src/vs/editor/contrib/format/common/formatActions.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "formatAction.label": "Форматировать код" + "formatDocument.label": "Форматировать документ", + "formatSelection.label": "Форматировать выбранный фрагмент" } \ No newline at end of file diff --git a/i18n/rus/src/vs/editor/node/textMate/TMSyntax.i18n.json b/i18n/rus/src/vs/editor/node/textMate/TMSyntax.i18n.json index 5bb6d19f211..26185961f1b 100644 --- a/i18n/rus/src/vs/editor/node/textMate/TMSyntax.i18n.json +++ b/i18n/rus/src/vs/editor/node/textMate/TMSyntax.i18n.json @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "invalid.embeddedLanguages": "Недопустимое значение в \"contributes.{0}.embeddedLanguages\". Оно должно быть сопоставлением объекта между именем области и языком. Указанное значение: {1}", "invalid.injectTo": "Недопустимое значение в \"contributes.{0}.injectTo\". Должен быть задан массив имен языковых областей. Указанное значение: {1}", "invalid.language": "Неизвестный язык в contributes.{0}.language. Указанное значение: {1}", "invalid.path.0": "В contributes.{0}.path требуется строка. Указанное значение: {1}", "invalid.path.1": "contributes.{0}.path ({1}) должен был быть включен в папку расширения ({2}). Это может сделать расширение непереносимым.", "invalid.scopeName": "В contributes.{0}.scopeName требуется строка. Указанное значение: {1}", "vscode.extension.contributes.grammars": "Добавляет разметчики TextMate.", + "vscode.extension.contributes.grammars.embeddedLanguages": "Сопоставление имени области и идентификатора языка, если грамматика содержит встроенные языки.", "vscode.extension.contributes.grammars.injectTo": "Список имен языковых областей, в которые вставляется эта грамматика.", "vscode.extension.contributes.grammars.language": "Идентификатор языка, для которого добавляется этот синтаксис.", "vscode.extension.contributes.grammars.path": "Путь к файлу tmLanguage. Путь указывается относительно папки расширения и обычно начинается с \"./syntaxes/\".", diff --git a/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json b/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json index 8db23f2b579..06e9724c38b 100644 --- a/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json +++ b/i18n/rus/src/vs/platform/extensionManagement/node/extensionManagementService.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "cancel": "Отмена", "doNotInstall": "Нет", "install": "Да", "installDependeciesConfirmation": "При установке \"{0}\" также устанавливаются зависимости. Вы хотите продолжить?", @@ -11,6 +12,14 @@ "invalidName": "Недопустимое расширение: несоответствие имени манифеста.", "invalidPublisher": "Недопустимое расширение: несоответствие издателя манифеста.", "invalidVersion": "Недопустимое расширение: несоответствие версии манифеста.", + "multipleDependentsError": "Не удается удалить расширение \"{0}\". От него зависят расширения \"{1}\", \"{2}\" и другие.", "notExists": "Не удалось найти расширение", - "restartCode": "Перезапустите код перед переустановкой {0}." + "ok": "ОК", + "restartCode": "Перезапустите код перед переустановкой {0}.", + "singleDependentError": "Не удается удалить расширение \"{0}\". От него зависит расширение \"{1}\".", + "twoDependentsError": "Не удается удалить расширение \"{0}\". От него зависят расширения \"{1}\" и \"{2}\".", + "uninstallAll": "Все", + "uninstallConfirmation": "Вы действительно хотите удалить \"{0}\"?", + "uninstallDependeciesConfirmation": "Вы хотите удалить \"{0}\" отдельно или вместе с зависимостями?", + "uninstallOnly": "Только" } \ No newline at end of file diff --git a/i18n/rus/src/vs/platform/extensions/common/extensionsRegistry.i18n.json b/i18n/rus/src/vs/platform/extensions/common/extensionsRegistry.i18n.json index 0200bc29633..df6edcd773b 100644 --- a/i18n/rus/src/vs/platform/extensions/common/extensionsRegistry.i18n.json +++ b/i18n/rus/src/vs/platform/extensions/common/extensionsRegistry.i18n.json @@ -4,18 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "extensionDescription.activationEvents1": "свойство \"{0}\" может быть опущено или должно быть типа \"string []\"", - "extensionDescription.activationEvents2": "оба свойства, \"{0}\" и \"{1}\", должны быть либо указаны, либо опущены", - "extensionDescription.empty": "Пустое описание расширения", - "extensionDescription.engines": "свойство \"{0}\" является обязательным и должно быть типа object", - "extensionDescription.engines.vscode": "свойство \"{0}\" является обязательным и должно иметь тип string", - "extensionDescription.extensionDependencies": "свойство \"{0}\" может быть опущено или должно быть типа \"string []\"", - "extensionDescription.main1": "свойство \"{0}\" может быть опущено или должно иметь тип string", - "extensionDescription.main2": "Ожидается, что функция main ({0}) будет включена в папку расширения ({1}). Из-за этого расширение может стать непереносимым.", - "extensionDescription.main3": "оба свойства, \"{0}\" и \"{1}\", должны быть либо указаны, либо опущены", - "extensionDescription.name": "свойство \"{0}\" является обязательным и должно иметь тип string", - "extensionDescription.publisher": "свойство \"{0}\" является обязательным и должно иметь тип string", - "extensionDescription.version": "свойство \"{0}\" является обязательным и должно иметь тип string", "vscode.extension.activationEvents": "События активации для расширения кода VS Code.", "vscode.extension.badges": "Массив эмблем, отображаемых на боковой панели страницы расширения Marketplace.", "vscode.extension.badges.description": "Описание эмблемы.", @@ -24,6 +12,7 @@ "vscode.extension.categories": "Категории, используемые коллекцией VS Code для классификации расширения.", "vscode.extension.contributes": "Все публикации расширения VS Code, представленные этим пакетом.", "vscode.extension.displayName": "Отображаемое имя расширения, используемого в коллекции VS Code.", + "vscode.extension.engines.vscode": "Для расширений VS Code указывает версию VS Code, с которой совместимо расширение. Она не может быть задана как \"*\". Например, ^0.10.5 сообщает о совместимости с минимальной версией VS Code 0.10.5.", "vscode.extension.extensionDependencies": "Зависимости от других расширений. Идентификатор расширения — всегда ${publisher}.${name}. Например: vscode.csharp.", "vscode.extension.galleryBanner": "Баннер, используемый в магазине VS Code.", "vscode.extension.galleryBanner.color": "Цвет баннера в заголовке страницы магазина VS Code.", diff --git a/i18n/rus/src/vs/workbench/browser/actions/openSettings.i18n.json b/i18n/rus/src/vs/workbench/browser/actions/openSettings.i18n.json index fea99be221d..a036aeb355d 100644 --- a/i18n/rus/src/vs/workbench/browser/actions/openSettings.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/actions/openSettings.i18n.json @@ -7,6 +7,7 @@ "defaultKeybindings": "Сочетания клавиш по умолчанию", "defaultKeybindingsHeader": "Перезапишите настраиваемое сочетание клавиш, поместив их в файл настраиваемых сочетаний клавиш.", "defaultName": "Параметры по умолчанию", + "defaultSettingsEditor": "Редактор параметров по умолчанию", "defaultSettingsHeader": "Перезапишите параметры, поместив их в файл параметров.", "defaultSettingsHeader2": "Наиболее часто используемые настройки см. по адресу http://go.microsoft.com/fwlink/?LinkId=808995.", "emptyKeybindingsHeader": "Поместите настраиваемые сочетания клавиш в этот файл, чтобы перезаписать клавиши по умолчанию.", diff --git a/i18n/rus/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json b/i18n/rus/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json index 8b6ad71cd4e..bf40f6bf36a 100644 --- a/i18n/rus/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/actions/toggleEditorLayout.i18n.json @@ -3,4 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "horizontalLayout": "Горизонтальная структура группы редакторов", + "toggleEditorGroupLayout": "Переключить вертикальную или горизонтальную структуру группы редакторов", + "verticalLayout": "Вертикальная структура группы редакторов", + "view": "Просмотреть" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json index 71865f52fd9..41b18dc4ca3 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editor.contribution.i18n.json @@ -6,9 +6,9 @@ { "allEditorsPicker": "Показать все открытые редакторы", "binaryDiffEditor": "Редактор двоичных несовпадений", - "centerEditorGroupPicker": "Показать редакторы в центральной группе", - "leftEditorGroupPicker": "Показать редакторы в левой группе", - "rightEditorGroupPicker": "Показать редакторы в правой группе", + "groupOnePicker": "Показать редакторы в первой группе", + "groupThreePicker": "Показать редакторы в третьей группе", + "groupTwoPicker": "Показать редакторы во второй группе", "textDiffEditor": "Редактор текстовых несовпадений", "textEditor": "Текстовый редактор", "view": "Просмотреть" diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editorActions.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editorActions.i18n.json index 1743a1e92c8..fabb47248c6 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editorActions.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editorActions.i18n.json @@ -14,12 +14,12 @@ "closeOtherEditorsInGroup": "Закрыть другие редакторы", "evenEditorGroups": "Уравнять ширину групп редакторов", "focusActiveEditorGroup": "Сфокусироваться на активной группе редактора", - "focusFirstEditorGroup": "Фокус на группу редакторов слева", + "focusFirstEditorGroup": "Фокус на первую группу редакторов", "focusLastEditorInStack": "Открыть последний редактор в группе", "focusNextGroup": "Фокус на следующую группу", "focusPreviousGroup": "Фокус на предыдущую группу", - "focusSecondEditorGroup": "Фокус на группу редакторов в центре", - "focusThirdEditorGroup": "Фокус на группу редакторов справа", + "focusSecondEditorGroup": "Фокус на вторую группу редакторов", + "focusThirdEditorGroup": "Фокус на третью группу редакторов", "keepEditor": "Сохранить редактор", "maximizeEditor": "Развернуть группу редакторов и скрыть боковую панель", "minimizeOtherEditorGroups": "Свернуть другие группы редакторов", @@ -27,8 +27,8 @@ "moveActiveGroupRight": "Переместить группу редакторов вправо", "moveEditorLeft": "Переместить редактор влево", "moveEditorRight": "Переместить редактор вправо", - "moveEditorToLeftGroup": "Переместить редактор в группу слева", - "moveEditorToRightGroup": "Переместить редактор в группу справа", + "moveEditorToNextGroup": "Переместить редактор в следующую группу", + "moveEditorToPreviousGroup": "Переместить редактор в предыдущую группу", "navigateEditorGroups": "Переход между группами редакторов", "navigateEditorHistoryByInput": "Открыть предыдущий редактор из журнала", "navigateNext": "Далее", @@ -38,12 +38,11 @@ "openPreviousEditor": "Открыть предыдущий редактор", "openPreviousEditorInGroup": "Открыть предыдущий недавно использованный редактор в группе", "openToSide": "Открыть сбоку", - "removeFromEditorHistory": "Удалить из журнала редакторов", "reopenClosedEditor": "Открыть закрытый редактор", "showAllEditors": "Показать все редакторы", - "showEditorsInCenterGroup": "Показать редакторы в центральной группе", + "showEditorsInFirstGroup": "Показать редакторы в первой группе", "showEditorsInGroup": "Показать редакторы в группе", - "showEditorsInLeftGroup": "Показать редакторы в левой группе", - "showEditorsInRightGroup": "Показать редакторы в правой группе", + "showEditorsInSecondGroup": "Показать редакторы во второй группе", + "showEditorsInThirdGroup": "Показать редакторы в третьей группе", "splitEditor": "Разделить редактор" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editorPart.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editorPart.i18n.json index 1e02b4e811e..b38c3928c2f 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editorPart.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editorPart.i18n.json @@ -4,8 +4,11 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "centerGroup": "По центру", "editorOpenError": "Невозможно открыть \"{0}\": {1}.", - "leftGroup": "Слева", - "rightGroup": "Справа" + "groupOneHorizontal": "По верхнему краю", + "groupOneVertical": "Слева", + "groupThreeHorizontal": "По нижнему краю", + "groupThreeVertical": "Справа", + "groupTwoHorizontal": "По центру", + "groupTwoVertical": "По центру" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json index 30a1ae4660a..a3ce595d861 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editorPicker.i18n.json @@ -6,7 +6,8 @@ { "entryAriaLabel": "{0}, выбор группы редакторов", "groupLabel": "Группа: {0}", - "noOpenedEditors": "Список открытых редакторов сейчас пуст", + "noOpenedEditors": "Список открытых редакторов в группе сейчас пуст.", + "noOpenedEditorsAllGroups": "Список открытых редакторов сейчас пуст.", "noResultsFound": "Соответствующие открытые редакторы не найдены", "noResultsFoundInGroup": "Соответствующие открытые редакторы не найдены в группе" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json b/i18n/rus/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json index 963de95d38d..4e6e6195915 100644 --- a/i18n/rus/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json +++ b/i18n/rus/src/vs/workbench/browser/parts/editor/editorStatus.i18n.json @@ -38,6 +38,7 @@ "selectEOL": "Выберите последовательность конца строки", "selectEncoding": "Выберите кодировку", "selectLanguageMode": "Выберите языковой режим", + "showLanguageExtensions": "Поиск \"{0}\" среди расширений Marketplace...", "singleSelection": "Строка {0}, столбец {1}", "singleSelectionRange": "Строка {0}, столбец {1} (выбрано {2})", "spacesSize": "Пробелов: {0}", diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json index 8b54650d608..bb07b9be4ec 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/breakpointWidget.i18n.json @@ -5,9 +5,9 @@ // Do not edit this file. It is machine generated. { "breakpointWidgetAriaLabel": "Выполнение программы прервется в этом месте, только если условие выполнится. Нажмите клавишу ВВОД для принятия или ESC для отмены.", - "breakpointWidgetExpressionPlaceholder": "Выполнить прерывание, если выражение равно \"True\"", + "breakpointWidgetExpressionPlaceholder": "Прервать выполнение, если выражение равно true. Нажмите клавишу ВВОД, чтобы принять, или ESC для отмены.", "breakpointWidgetHitCountAriaLabel": "Выполнение программы прервется в этом месте, только если достигнуто определенное количество обращений. Нажмите клавишу ВВОД для принятия или ESC для отмены.", - "breakpointWidgetHitCountPlaceholder": "Выполнить прерывание при определенном количестве обращений", + "breakpointWidgetHitCountPlaceholder": "Прервать при определенном количестве обращений. Нажмите клавишу ВВОД, чтобы принять, или ESC для отмены.", "expression": "Выражение", "hitCount": "Количество обращений" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/debug/browser/debugActions.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/browser/debugActions.i18n.json index 411c89a8ecf..fe4615c5816 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/browser/debugActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/browser/debugActions.i18n.json @@ -13,7 +13,6 @@ "conditionalBreakpointEditorAction": "Отладка: добавить условную точку останова…", "continueDebug": "Продолжить", "deactivateBreakpoints": "Отключить точки останова", - "debugActionLabelAndKeybinding": "{0} ({1})", "debugAddToWatch": "Отладка: добавить контрольное значение", "debugConsoleAction": "Консоль отладки", "debugEvaluate": "Отладка: вычисление", @@ -21,6 +20,7 @@ "disableAllBreakpoints": "Отключить все точки останова", "disconnectDebug": "Отключить", "editConditionalBreakpoint": "Изменить точку останова…", + "editWatchExpression": "Изменить выражение", "enableAllBreakpoints": "Включить все точки останова", "launchJsonNeedsConfigurtion": "Настройте или исправьте \"launch.json\"", "openLaunchJson": "Открыть {0}", @@ -32,7 +32,6 @@ "removeBreakpoint": "Удалить точку останова", "removeWatchExpression": "Удалить выражение", "renameFunctionBreakpoint": "Переименовать точку останова в функции", - "renameWatchExpression": "Переименовать выражение", "restartDebug": "Перезапустить", "restartFrame": "Перезапустить кадр", "runToCursor": "Отладка: выполнить до текущей позиции", diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json index 28e05215d6d..7da9766c32b 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debug.contribution.i18n.json @@ -4,14 +4,13 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { - "allowBreakpointsEverywhere": "Разрешает задание точки останова для всех файлов с любым расширением.", + "allowBreakpointsEverywhere": "Разрешает задание точки останова в любом файле", "debug": "Отладка", "debugCategory": "Отладка", "debugConfigurationTitle": "Отладка", "debugErrorEditor": "Ошибка при отладке", "debugPanel": "Консоль отладки", - "launchConfigDoesNotExist": "Конфигурация запуска \"{0}\" не существует.", - "openExplorerOnEnd": "Автоматически открывать мини-приложение просмотра проводника по завершении сеанса отладки.", + "openExplorerOnEnd": "Автоматически открывать мини-приложение проводника в конце сеанса отладки", "toggleDebugPanel": "Консоль отладки", "toggleDebugViewlet": "Показать отладочные сведения", "view": "Просмотреть" diff --git a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json index 28044caf19e..5db25837880 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/electron-browser/debugViewer.i18n.json @@ -12,6 +12,7 @@ "functionBreakpointsNotSupported": "Точки останова функций не поддерживаются в этом типе отладки", "loadMoreStackFrames": "Загрузить больше кадров стека", "paused": "приостановлено", + "process": "Процесс", "running": "выполняется", "stackFrameAriaLabel": "Кадр стека {0}, строка {1} {2}, стек вызовов, отладка", "thread": "Поток", diff --git a/i18n/rus/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json b/i18n/rus/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json index 852200a7c11..091304950ad 100644 --- a/i18n/rus/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/debug/node/debugAdapter.i18n.json @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "debugConfigurationNames": "Конфигурации, которые будут запущены в рамках этой \"составной\" конфигурации. Учитываются, только если тип конфигурации — \"composite\".", "debugLinuxConfiguration": "Атрибуты конфигурации запуска для Linux.", "debugName": "Имя конфигурации; отображается в раскрывающемся меню конфигурации запуска.", "debugOSXConfiguration": "Атрибуты конфигурации запуска для OS X.", diff --git a/i18n/rus/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json b/i18n/rus/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json index 1f7b7c4a951..a34720eebcf 100644 --- a/i18n/rus/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.i18n.json @@ -6,20 +6,39 @@ { "ConfigureWorkspaceRecommendations.noWorkspace": "Рекомендации доступны только для папки рабочей области.", "OpenExtensionsFile.failed": "Не удается создать файл \"extensions.json\" в папке \".vscode\" ({0}).", - "OpenGlobalExtensionsStorageFile.failed": "Не удалось создать файл \"extensions.json\" внутри папки \"{0}\" ({1}).", + "Uninstalling": "Идет удаление", "builtin": "Встроенное", "clearExtensionsInput": "Очистить входные данные расширений", "configureWorkspaceRecommendedExtensions": "Настроить рекомендуемые расширения (рабочая область)", - "deleteSure": "Действительно удалить \"{0}\"?", + "disableAction": "Отключить", + "disableAll": "Отключить все", + "disableAllWorkspace": "Отключить все (рабочая область)", + "disableAlwaysAction.label": "Отключить", + "disableForWorkspaceAction": "Рабочая область", + "disableForWorkspaceAction.label": "Отключить (рабочая область)", + "disableGloballyAction": "Всегда", "enableAction": "Включить", + "enableAll": "Включить все", + "enableAllWorkspace": "Включить все (рабочая область)", + "enableAlwaysAction.label": "Включить", + "enableForWorkspaceAction": "Рабочая область", + "enableForWorkspaceAction.label": "Включить (рабочая область)", + "enableGloballyAction": "Всегда", "installAction": "Установить", "installExtensions": "Установить расширения", "installVSIX": "Установка из VSIX...", "installing": "Идет установка", "openExtensionsFolder": "Открыть папку расширений", - "postUninstallMessage": "Расширение \"{0}\" было успешно удалено. Чтобы отключить его, выполните перезапуск.", - "restart": "Чтобы включить это расширение, необходимо перезапустить это окно VS Code.\n\nПродолжить?", - "restartNow": "Перезагрузка", + "postDisableMessage": "Перезагрузить это окно, чтобы отключить расширение \"{0}\"?", + "postDisableTooltip": "Перезагрузка для отключения", + "postEnableMessage": "Перезагрузить это окно, чтобы включить расширение \"{0}\"?", + "postEnableTooltip": "Перезагрузка для включения", + "postInstallMessage": "Перезагрузить это окно, чтобы активировать расширение \"{0}\"?", + "postInstallTooltip": "Перезагрузка для активации", + "postUninstallMessage": "Перезагрузить это окно, чтобы деактивировать расширение \"{0}\"?", + "postUninstallTooltip": "Перезагрузка для деактивации", + "reloadAction": "Перезагрузить", + "reloadNow": "Перезагрузить сейчас", "showDisabledExtensions": "Показать отключенные расширения", "showInstalledExtensions": "Показать установленные расширения", "showOutdatedExtensions": "Показать устаревшие расширения", @@ -27,7 +46,7 @@ "showRecommendedExtensions": "Показать рекомендуемые расширения", "showWorkspaceRecommendedExtensions": "Показать рекомендуемые расширения рабочей области", "toggleExtensionsViewlet": "Показать расширения", - "uninstall": "Удалить", + "uninstallAction": "Удалить", "updateAction": "Обновить", "updateAll": "Обновить все расширения" } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/git/node/git.lib.i18n.json b/i18n/rus/src/vs/workbench/parts/git/node/git.lib.i18n.json index 54fbd1ada7b..03b27aecc20 100644 --- a/i18n/rus/src/vs/workbench/parts/git/node/git.lib.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/git/node/git.lib.i18n.json @@ -4,5 +4,6 @@ *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. { + "errorBuffer": "Не удается открыть файл из GIT.", "fileBinaryError": "Похоже, файл является двоичным, и его нельзя открыть как текстовый." } \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/html/browser/webview.i18n.json b/i18n/rus/src/vs/workbench/parts/html/browser/webview.i18n.json index 8b6ad71cd4e..20514519e02 100644 --- a/i18n/rus/src/vs/workbench/parts/html/browser/webview.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/html/browser/webview.i18n.json @@ -3,4 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Do not edit this file. It is machine generated. -{} \ No newline at end of file +{ + "devtools.webview": "Разработчик: средства веб-представления" +} \ No newline at end of file diff --git a/i18n/rus/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json b/i18n/rus/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json index 911fa595a7b..edcba688639 100644 --- a/i18n/rus/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/quickopen/browser/gotoLineHandler.i18n.json @@ -6,7 +6,7 @@ { "cannotRunGotoLine": "Чтобы перейти к строке, сначала откройте текстовый файл", "gotoLine": "Перейти к строке...", - "gotoLineColumnLabel": "Перейти к строке {0} и столбцу {1}", + "gotoLineColumnLabel": "Перейти к строке {0} и символу {1}", "gotoLineHandlerAriaLabel": "Введите номер строки, к которой нужно перейти.", "gotoLineLabel": "Перейти к строке {0}", "gotoLineLabelEmpty": "Введите номер строки для перехода", diff --git a/i18n/rus/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json b/i18n/rus/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json index d3b355a74af..c5e248ed1d1 100644 --- a/i18n/rus/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/quickopen/browser/gotoSymbolHandler.i18n.json @@ -8,7 +8,7 @@ "array": "массивы ({0})", "boolean": "логические значения ({0})", "cannotRunGotoSymbol": "Чтобы перейти к символу, сначала откройте текстовый файл", - "cannotRunGotoSymbolInFile": "К сожалению, у нас нет символьной информации для файла", + "cannotRunGotoSymbolInFile": "Нет символьной информации для файла.", "class": "классы ({0})", "entryAriaLabel": "{0}, символы", "enum": "перечисления ({0})", diff --git a/i18n/rus/src/vs/workbench/parts/update/electron-browser/update.i18n.json b/i18n/rus/src/vs/workbench/parts/update/electron-browser/update.i18n.json index 9a044906abc..1886b31ba90 100644 --- a/i18n/rus/src/vs/workbench/parts/update/electron-browser/update.i18n.json +++ b/i18n/rus/src/vs/workbench/parts/update/electron-browser/update.i18n.json @@ -5,9 +5,14 @@ // Do not edit this file. It is machine generated. { "downloadNow": "Скачать сейчас", + "insiderBuilds": "Ежедневные сборки и выпуски для участников программы предварительной оценки.", "later": "Позже", + "license": "Прочитать условия лицензии", + "licenseChanged": "Условия использования лицензии изменились, ознакомьтесь с ними.", + "neverShowAgain": "Больше не показывать", "noUpdatesAvailable": "В настоящее время нет доступных обновлений.", "read the release notes": "Вас приветствует {0} v{1}! Вы хотите прочитать заметки о выпуске?", + "readmore": "Подробнее", "releaseNotes": "Заметки о выпуске", "showReleaseNotes": "Показать заметки о выпуске", "thereIsUpdateAvailable": "Доступно обновление.", diff --git a/package.json b/package.json index bb9b77963bc..1608a3bd52e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "code-oss-dev", "version": "1.8.0", "electronVersion": "1.3.8", - "distro": "53e30f0e2907d30c579b0ef07de97c586e6750a4", + "distro": "cc6a2710b81e898b8cde2b51ba29e178980009e8", "author": { "name": "Microsoft Corporation" }, diff --git a/src/bootstrap.js b/src/bootstrap.js index ae4e67c1488..022aa50b6a3 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -98,9 +98,9 @@ if (!process.env['VSCODE_ALLOW_IO']) { write: function () { /* No OP */ } }); - process.__defineGetter__('stdout', function() { return writable; }); - process.__defineGetter__('stderr', function() { return writable; }); - process.__defineGetter__('stdin', function() { return writable; }); + process.__defineGetter__('stdout', function () { return writable; }); + process.__defineGetter__('stderr', function () { return writable; }); + process.__defineGetter__('stdin', function () { return writable; }); } // Handle uncaught exceptions diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 1a85e88af61..fa6ea706b93 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -14,6 +14,8 @@ class ZoomManager { public static INSTANCE = new ZoomManager(); private _zoomLevel: number = 0; + private _zoomFactor: number = 0; + private _pixelRatioCache: number = 0; private _pixelRatioComputed: boolean = false; @@ -34,6 +36,14 @@ class ZoomManager { this._onDidChangeZoomLevel.fire(this._zoomLevel); } + public getZoomFactor(): number { + return this._zoomFactor; + } + + public setZoomFactor(zoomFactor: number): void { + this._zoomFactor = zoomFactor; + } + public getPixelRatio(): number { if (!this._pixelRatioComputed) { this._pixelRatioCache = this._computePixelRatio(); @@ -54,15 +64,23 @@ class ZoomManager { } } +/** A zoom index, e.g. 1, 2, 3 */ export function getZoomLevel(): number { return ZoomManager.INSTANCE.getZoomLevel(); } +/** The zoom scale for an index, e.g. 1, 1.2, 1.4 */ +export function getZoomFactor(): number { + return ZoomManager.INSTANCE.getZoomFactor(); +} export function getPixelRatio(): number { return ZoomManager.INSTANCE.getPixelRatio(); } export function setZoomLevel(zoomLevel: number): void { ZoomManager.INSTANCE.setZoomLevel(zoomLevel); } +export function setZoomFactor(zoomFactor: number): void { + ZoomManager.INSTANCE.setZoomFactor(zoomFactor); +} export function onDidChangeZoomLevel(callback: (zoomLevel: number) => void): IDisposable { return ZoomManager.INSTANCE.onDidChangeZoomLevel(callback); } diff --git a/src/vs/base/browser/htmlContentRenderer.ts b/src/vs/base/browser/htmlContentRenderer.ts index c01045fe8ae..38db8a72cca 100644 --- a/src/vs/base/browser/htmlContentRenderer.ts +++ b/src/vs/base/browser/htmlContentRenderer.ts @@ -90,6 +90,42 @@ function _renderHtml(content: IHTMLContentElement, options: RenderOptions = {}): const withInnerHTML = new TPromise(c => signalInnerHTML = c); const renderer = new marked.Renderer(); + renderer.image = (href: string, title: string, text: string) => { + let dimensions = []; + if (href) { + const splitted = href.split('|').map(s => s.trim()); + href = splitted[0]; + const parameters = splitted[1]; + if (parameters) { + const heightFromParams = /height=(\d+)/.exec(parameters); + const widthFromParams = /width=(\d+)/.exec(parameters); + const height = (heightFromParams && heightFromParams[1]); + const width = (widthFromParams && widthFromParams[1]); + const widthIsFinite = isFinite(parseInt(width)); + const heightIsFinite = isFinite(parseInt(height)); + if (widthIsFinite) { + dimensions.push(`width="${width}"`); + } + if (heightIsFinite) { + dimensions.push(`height="${height}"`); + } + } + } + let attributes: string[] = []; + if (href) { + attributes.push(`src="${href}"`); + } + if (text) { + attributes.push(`alt="${text}"`); + } + if (title) { + attributes.push(`title="${title}"`); + } + if (dimensions.length) { + attributes = attributes.concat(dimensions); + } + return ''; + }; renderer.link = (href, title, text): string => { return `${text}`; }; diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 83b863c2a49..f2e40528c9c 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -694,10 +694,6 @@ export class SelectActionItem extends BaseActionItem { } } - public set enabled(value: boolean) { - this.selectBox.enabled = value; - } - public blur(): void { if (this.selectBox) { this.selectBox.blur(); diff --git a/src/vs/base/common/map.ts b/src/vs/base/common/map.ts index a2f048b67ed..7445af47dce 100644 --- a/src/vs/base/common/map.ts +++ b/src/vs/base/common/map.ts @@ -310,7 +310,7 @@ interface Node { */ export class TrieMap { - static PathSplitter = s => s.split(/[\\/]/); + static PathSplitter = s => s.split(/[\\/]/).filter(s => !!s); private _splitter: (s: string) => string[]; private _root: Node = { children: Object.create(null) }; @@ -345,6 +345,22 @@ export class TrieMap { node.element = element; } + lookUp(path: string): E { + const parts = this._splitter(path); + + let {children} = this._root; + let node: Node; + for (const part of parts) { + node = children[part]; + if (!node) { + return; + } + children = node.children; + } + + return node.element; + } + findSubstr(path: string): E { const parts = this._splitter(path); @@ -367,4 +383,22 @@ export class TrieMap { return lastNode.element; } } + + findSuperstr(path: string): TrieMap { + const parts = this._splitter(path); + + let {children} = this._root; + let node: Node; + for (const part of parts) { + node = children[part]; + if (!node) { + return; + } + children = node.children; + } + + const result = new TrieMap(this._splitter); + result._root = node; + return result; + } } diff --git a/src/vs/base/test/browser/htmlContent.test.ts b/src/vs/base/test/browser/htmlContent.test.ts index 02fcab11068..5a6b0e63239 100644 --- a/src/vs/base/test/browser/htmlContent.test.ts +++ b/src/vs/base/test/browser/htmlContent.test.ts @@ -5,6 +5,7 @@ 'use strict'; import * as assert from 'assert'; +import { marked } from 'vs/base/common/marked/marked'; import { renderHtml } from 'vs/base/browser/htmlContentRenderer'; suite('HtmlContent', () => { @@ -155,4 +156,46 @@ suite('HtmlContent', () => { assert.strictEqual(result.children.length, 0); assert.strictEqual(result.innerHTML, '**bold**'); }); + test('image rendering conforms to default', () => { + const renderableContent = { + markdown: "![image](someimageurl 'caption')" + }; + const result: HTMLElement = renderHtml(renderableContent); + const renderer = new marked.Renderer(); + const imageFromMarked = marked(renderableContent.markdown, { + sanitize: true, + renderer + }).trim(); + assert.strictEqual(result.innerHTML, imageFromMarked); + }); + test('image rendering conforms to default without title', () => { + const renderableContent = { + markdown: "![image](someimageurl)" + }; + const result: HTMLElement = renderHtml(renderableContent); + const renderer = new marked.Renderer(); + const imageFromMarked = marked(renderableContent.markdown, { + sanitize: true, + renderer + }).trim(); + assert.strictEqual(result.innerHTML, imageFromMarked); + }); + test('image width from title params', () => { + var result: HTMLElement = renderHtml({ + markdown: "![image](someimageurl|width=100 'caption')" + }); + assert.strictEqual(result.innerHTML, `

image

`); + }); + test('image height from title params', () => { + var result: HTMLElement = renderHtml({ + markdown: "![image](someimageurl|height=100 'caption')" + }); + assert.strictEqual(result.innerHTML, `

image

`); + }); + test('image width and height from title params', () => { + var result: HTMLElement = renderHtml({ + markdown: "![image](someimageurl|height=200,width=100 'caption')" + }); + assert.strictEqual(result.innerHTML, `

image

`); + }); }); \ No newline at end of file diff --git a/src/vs/base/test/common/map.test.ts b/src/vs/base/test/common/map.test.ts index 39545b12627..d3ae15609e5 100644 --- a/src/vs/base/test/common/map.test.ts +++ b/src/vs/base/test/common/map.test.ts @@ -290,4 +290,34 @@ suite('Map', () => { assert.equal(map.findSubstr('/user/foo/bar/far/boo'), 1); }); + + test('TrieMap - lookup', function () { + + const map = new TrieMap(TrieMap.PathSplitter); + map.insert('/user/foo/bar', 1); + map.insert('/user/foo', 2); + map.insert('/user/foo/flip/flop', 3); + + assert.equal(map.lookUp('/foo'), undefined); + assert.equal(map.lookUp('/user'), undefined); + assert.equal(map.lookUp('/user/foo'), 2); + assert.equal(map.lookUp('/user/foo/bar'), 1); + assert.equal(map.lookUp('/user/foo/bar/boo'), undefined); + }); + + test('TrieMap - superstr', function () { + + const map = new TrieMap(TrieMap.PathSplitter); + map.insert('/user/foo/bar', 1); + map.insert('/user/foo', 2); + map.insert('/user/foo/flip/flop', 3); + + const supMap = map.findSuperstr('/user'); + + assert.equal(supMap.lookUp('foo'), 2); + assert.equal(supMap.lookUp('foo/bar'), 1); + assert.equal(supMap.lookUp('foo/flip/flop'), 3); + assert.equal(supMap.lookUp('foo/flip/flop/bar'), undefined); + assert.equal(supMap.lookUp('user'), undefined); + }); }); diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 35e0f87c387..4e6bc1a1a63 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -203,56 +203,10 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo const menu = instantiationService.createInstance(VSCodeMenu); menu.ready(); - // Install JumpList on Windows + // Install JumpList on Windows (keep updated when windows open) if (platform.isWindows) { - const jumpList: Electron.JumpListCategory[] = []; - - // Tasks - jumpList.push({ - type: 'tasks', - items: [ - { - type: 'task', - title: nls.localize('newWindow', "New Window"), - description: nls.localize('newWindowDesc', "Opens a new window"), - program: process.execPath, - args: '-n', // force new window - iconPath: process.execPath, - iconIndex: 0 - } - ] - }); - - // Recent Folders - const folders = windowsMainService.getRecentPathsList().folders; - if (folders.length > 0) { - jumpList.push({ - type: 'custom', - name: 'Recent Folders', - items: windowsMainService.getRecentPathsList().folders.slice(0, 7 /* limit number of entries here */).map(folder => { - return { - type: 'task', - title: getPathLabel(folder), - description: nls.localize('folderDesc', "{0} {1}", path.basename(folder), getPathLabel(path.dirname(folder))), - program: process.execPath, - args: folder, // open folder, - iconPath: 'explorer.exe', // simulate folder icon - iconIndex: 0 - }; - }) - }); - } - - // Recent - jumpList.push({ - type: 'recent' // this enables to show files in the "recent" category - }); - - try { - app.setJumpList(jumpList); - } catch (error) { - logService.log('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors - } + updateJumpList(windowsMainService, logService); + windowsMainService.onOpen(() => updateJumpList(windowsMainService, logService)); } // Setup auto update @@ -268,6 +222,57 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo } } +function updateJumpList(windowsMainService: IWindowsMainService, logService: ILogService): void { + const jumpList: Electron.JumpListCategory[] = []; + + // Tasks + jumpList.push({ + type: 'tasks', + items: [ + { + type: 'task', + title: nls.localize('newWindow', "New Window"), + description: nls.localize('newWindowDesc', "Opens a new window"), + program: process.execPath, + args: '-n', // force new window + iconPath: process.execPath, + iconIndex: 0 + } + ] + }); + + // Recent Folders + const folders = windowsMainService.getRecentPathsList().folders; + if (folders.length > 0) { + jumpList.push({ + type: 'custom', + name: nls.localize('recentFolders', "Recent Folders"), + items: windowsMainService.getRecentPathsList().folders.slice(0, 7 /* limit number of entries here */).map(folder => { + return { + type: 'task', + title: path.basename(folder) || folder, // use the base name to show shorter entries in the list + description: nls.localize('folderDesc', "{0} {1}", path.basename(folder), getPathLabel(path.dirname(folder))), + program: process.execPath, + args: `"${folder}"`, // open folder (use quotes to support paths with whitespaces), + iconPath: 'explorer.exe', // simulate folder icon + iconIndex: 0 + }; + }) + }); + } + + // Recent + jumpList.push({ + type: 'recent' // this enables to show files in the "recent" category + }); + + try { + app.setJumpList(jumpList); + } catch (error) { + logService.log('#setJumpList', error); // since setJumpList is relatively new API, make sure to guard for errors + } +} + function setupIPC(accessor: ServicesAccessor): TPromise { const logService = accessor.get(ILogService); const environmentService = accessor.get(IEnvironmentService); diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index 6847cad723c..a89df31e70b 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -140,30 +140,28 @@ export class VSCodeMenu { updateMenu = true; } - if (config && config.workbench) { - const newSidebarLocation = config.workbench.sideBar && config.workbench.sideBar.location || 'left'; - if (newSidebarLocation !== this.currentSidebarLocation) { - this.currentSidebarLocation = newSidebarLocation; - updateMenu = true; - } + const newSidebarLocation = config && config.workbench && config.workbench.sideBar && config.workbench.sideBar.location || 'left'; + if (newSidebarLocation !== this.currentSidebarLocation) { + this.currentSidebarLocation = newSidebarLocation; + updateMenu = true; + } - let newStatusbarVisible = config.workbench.statusBar && config.workbench.statusBar.visible; - if (typeof newStatusbarVisible !== 'boolean') { - newStatusbarVisible = true; - } - if (newStatusbarVisible !== this.currentStatusbarVisible) { - this.currentStatusbarVisible = newStatusbarVisible; - updateMenu = true; - } + let newStatusbarVisible = config && config.workbench && config.workbench.statusBar && config.workbench.statusBar.visible; + if (typeof newStatusbarVisible !== 'boolean') { + newStatusbarVisible = true; + } + if (newStatusbarVisible !== this.currentStatusbarVisible) { + this.currentStatusbarVisible = newStatusbarVisible; + updateMenu = true; + } - let newActivityBarVisible = config.workbench.activityBar && config.workbench.activityBar.visible; - if (typeof newActivityBarVisible !== 'boolean') { - newActivityBarVisible = true; - } - if (newActivityBarVisible !== this.currentActivityBarVisible) { - this.currentActivityBarVisible = newActivityBarVisible; - updateMenu = true; - } + let newActivityBarVisible = config && config.workbench && config.workbench.activityBar && config.workbench.activityBar.visible; + if (typeof newActivityBarVisible !== 'boolean') { + newActivityBarVisible = true; + } + if (newActivityBarVisible !== this.currentActivityBarVisible) { + this.currentActivityBarVisible = newActivityBarVisible; + updateMenu = true; } if (handleMenu && updateMenu) { diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 2d90236b64f..8d55160477b 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -16,6 +16,7 @@ import { ILogService } from 'vs/code/electron-main/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { parseArgs, ParsedArgs } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/product'; +import { getCommonHTTPHeaders } from 'vs/platform/environment/common/http'; export interface IWindowState { width?: number; @@ -29,6 +30,7 @@ export interface IWindowCreationOptions { state: IWindowState; extensionDevelopmentPath?: string; allowFullscreen?: boolean; + titleBarStyle?: 'native' | 'custom'; } export enum WindowMode { @@ -107,6 +109,7 @@ export interface IWindowSettings { reopenFolders: 'all' | 'one' | 'none'; restoreFullscreen: boolean; zoomLevel: number; + titleBarStyle: 'native' | 'custom'; } export class VSCodeWindow { @@ -176,10 +179,32 @@ export class VSCodeWindow { options.icon = path.join(this.environmentService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s) } + if (this.options.titleBarStyle === 'custom' && platform.isMacintosh) { + const isDev = !this.environmentService.isBuilt || this.environmentService.extensionDevelopmentPath; + if (!isDev) { + options.titleBarStyle = 'hidden'; // not enabled when developing due to https://github.com/electron/electron/issues/3647 + } + } + // Create the browser window. this._win = new BrowserWindow(options); this._id = this._win.id; + // TODO@joao: hook this up to some initialization routine + // this causes a race between setting the headers and doing + // a request that needs them. chances are low + getCommonHTTPHeaders().done(headers => { + if (!this._win) { + return; + } + + const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*']; + + this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => { + cb({ cancel: false, requestHeaders: objects.assign(details.requestHeaders, headers) }); + }); + }); + if (isFullscreenOrMaximized) { this.win.maximize(); diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 4530d940889..f7255e0dbd5 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -18,7 +18,7 @@ import { EventEmitter } from 'events'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IStorageService } from 'vs/code/electron-main/storage'; import { IPath, VSCodeWindow, ReadyState, IWindowConfiguration, IWindowState as ISingleWindowState, defaultWindowState, IWindowSettings } from 'vs/code/electron-main/window'; -import { ipcMain as ipc, app, screen, crashReporter, BrowserWindow, dialog, shell } from 'electron'; +import { ipcMain as ipc, app, screen, BrowserWindow, dialog } from 'electron'; import { IPathWithLineAndColumn, parseLineAndColumnAware } from 'vs/code/electron-main/paths'; import { ILifecycleService } from 'vs/code/electron-main/lifecycle'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -118,9 +118,10 @@ export interface IWindowsMainService { getWindowById(windowId: number): VSCodeWindow; getWindows(): VSCodeWindow[]; getWindowCount(): number; - getRecentPathsList(): IRecentPathsList; + getRecentPathsList(workspacePath?: string, filesToOpen?: IPath[]): IRecentPathsList; removeFromRecentPathsList(path: string); clearRecentPathsList(): void; + toggleMenuBar(windowId: number): void; } export class WindowsManager implements IWindowsMainService, IWindowEventService { @@ -213,20 +214,6 @@ export class WindowsManager implements IWindowsMainService, IWindowEventService }, 100); }); - ipc.on('vscode:startCrashReporter', (event: any, config: any) => { - this.logService.log('IPC#vscode:startCrashReporter'); - - crashReporter.start(config); - }); - - ipc.on('vscode:windowOpen', (event, paths: string[], forceNewWindow?: boolean) => { - this.logService.log('IPC#vscode-windowOpen: ', paths); - - if (paths && paths.length) { - this.open({ cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: forceNewWindow }); - } - }); - ipc.on('vscode:workbenchLoaded', (event, windowId: number) => { this.logService.log('IPC#vscode-workbenchLoaded'); @@ -239,157 +226,6 @@ export class WindowsManager implements IWindowsMainService, IWindowEventService } }); - ipc.on('vscode:closeFolder', (event, windowId: number) => { - this.logService.log('IPC#vscode-closeFolder'); - - const win = this.getWindowById(windowId); - if (win) { - this.open({ cli: this.environmentService.args, forceEmpty: true, windowToUse: win }); - } - }); - - ipc.on('vscode:openNewWindow', () => { - this.logService.log('IPC#vscode-openNewWindow'); - - this.openNewWindow(); - }); - - ipc.on('vscode:toggleFullScreen', (event, windowId: number) => { - this.logService.log('IPC#vscode:toggleFullScreen'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.toggleFullScreen(); - } - }); - - ipc.on('vscode:setFullScreen', (event, windowId: number, fullscreen: boolean) => { - this.logService.log('IPC#vscode:setFullScreen'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.win.setFullScreen(fullscreen); - } - }); - - ipc.on('vscode:toggleDevTools', (event, windowId: number) => { - this.logService.log('IPC#vscode:toggleDevTools'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.win.webContents.toggleDevTools(); - } - }); - - ipc.on('vscode:openDevTools', (event, windowId: number) => { - this.logService.log('IPC#vscode:openDevTools'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.win.webContents.openDevTools(); - vscodeWindow.win.show(); - } - }); - - ipc.on('vscode:setRepresentedFilename', (event, windowId: number, fileName: string) => { - this.logService.log('IPC#vscode:setRepresentedFilename'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.win.setRepresentedFilename(fileName); - } - }); - - ipc.on('vscode:setMenuBarVisibility', (event, windowId: number, visibility: boolean) => { - this.logService.log('IPC#vscode:setMenuBarVisibility'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.win.setMenuBarVisibility(visibility); - } - }); - - ipc.on('vscode:flashFrame', (event, windowId: number) => { - this.logService.log('IPC#vscode:flashFrame'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.win.flashFrame(!vscodeWindow.win.isFocused()); - } - }); - - ipc.on('vscode:openRecent', (event, windowId: number) => { - this.logService.log('IPC#vscode:openRecent'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - const recents = this.getRecentPathsList(vscodeWindow.config.workspacePath, vscodeWindow.config.filesToOpen); - - vscodeWindow.send('vscode:openRecent', recents.files, recents.folders); - } - }); - - ipc.on('vscode:focusWindow', (event, windowId: number) => { - this.logService.log('IPC#vscode:focusWindow'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.win.focus(); - } - }); - - ipc.on('vscode:showWindow', (event, windowId: number) => { - this.logService.log('IPC#vscode:showWindow'); - - let vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.win.show(); - } - }); - - ipc.on('vscode:setDocumentEdited', (event, windowId: number, edited: boolean) => { - this.logService.log('IPC#vscode:setDocumentEdited'); - - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow && vscodeWindow.win.isDocumentEdited() !== edited) { - vscodeWindow.win.setDocumentEdited(edited); - } - }); - - ipc.on('vscode:toggleMenuBar', (event, windowId: number) => { - this.logService.log('IPC#vscode:toggleMenuBar'); - - // Update in settings - const menuBarHidden = this.storageService.getItem(VSCodeWindow.menuBarHiddenKey, false); - const newMenuBarHidden = !menuBarHidden; - this.storageService.setItem(VSCodeWindow.menuBarHiddenKey, newMenuBarHidden); - - // Update across windows - WindowsManager.WINDOWS.forEach(w => w.setMenuBarVisibility(!newMenuBarHidden)); - - // Inform user if menu bar is now hidden - if (newMenuBarHidden) { - const vscodeWindow = this.getWindowById(windowId); - if (vscodeWindow) { - vscodeWindow.send('vscode:showInfoMessage', nls.localize('hiddenMenuBar', "You can still access the menu bar by pressing the **Alt** key.")); - } - } - }); - - ipc.on('vscode:setHeaders', (event, windowId: number, urls: string[], headers: any) => { - this.logService.log('IPC#vscode:setHeaders'); - - const vscodeWindow = this.getWindowById(windowId); - - if (!vscodeWindow || !urls || !urls.length || !headers) { - return; - } - - vscodeWindow.win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => { - cb({ cancel: false, requestHeaders: assign(details.requestHeaders, headers) }); - }); - }); - ipc.on('vscode:broadcast', (event, windowId: number, target: string, broadcast: { channel: string; payload: any; }) => { if (broadcast.channel && !types.isUndefinedOrNull(broadcast.payload)) { this.logService.log('IPC#vscode:broadcast', target, broadcast.channel, broadcast.payload); @@ -413,47 +249,6 @@ export class WindowsManager implements IWindowsMainService, IWindowEventService } }); - ipc.on('vscode:log', (event, logEntry: ILogEntry) => { - const args = []; - try { - const parsed = JSON.parse(logEntry.arguments); - args.push(...Object.getOwnPropertyNames(parsed).map(o => parsed[o])); - } catch (error) { - args.push(logEntry.arguments); - } - - console[logEntry.severity].apply(console, args); - }); - - ipc.on('vscode:closeExtensionHostWindow', (event, extensionDevelopmentPath: string) => { - this.logService.log('IPC#vscode:closeExtensionHostWindow', extensionDevelopmentPath); - - const windowOnExtension = this.findWindow(null, null, extensionDevelopmentPath); - if (windowOnExtension) { - windowOnExtension.win.close(); - } - }); - - ipc.on('vscode:switchWindow', (event, windowId: number) => { - const windows = this.getWindows(); - const window = this.getWindowById(windowId); - window.send('vscode:switchWindow', windows.map(w => { - return { path: w.openedWorkspacePath, title: w.win.getTitle(), id: w.id }; - })); - }); - - ipc.on('vscode:showItemInFolder', (event, path: string) => { - this.logService.log('IPC#vscode-showItemInFolder'); - - shell.showItemInFolder(path); - }); - - ipc.on('vscode:openExternal', (event, url: string) => { - this.logService.log('IPC#vscode-openExternal'); - - shell.openExternal(url); - }); - this.updateService.on('update-downloaded', (update: IUpdate) => { this.sendToFocused('vscode:telemetry', { eventName: 'update:downloaded', data: { version: update.version } }); @@ -759,18 +554,23 @@ export class WindowsManager implements IWindowsMainService, IWindowEventService public removeFromRecentPathsList(path: string): void { const mru = this.getRecentPathsList(); + let update = false; let index = mru.files.indexOf(path); if (index >= 0) { mru.files.splice(index, 1); + update = true; } index = mru.folders.indexOf(path); if (index >= 0) { mru.folders.splice(index, 1); + update = true; } - this.storageService.setItem(WindowsManager.recentPathsListStorageKey, mru); + if (update) { + this.storageService.setItem(WindowsManager.recentPathsListStorageKey, mru); + } } public clearRecentPathsList(): void { @@ -883,6 +683,8 @@ export class WindowsManager implements IWindowsMainService, IWindowEventService { workspacePath: candidate }; } } catch (error) { + this.removeFromRecentPathsList(candidate); // since file does not seem to exist anymore, remove from recent + if (ignoreFileNotFound) { return { filePath: candidate, createFilePath: true }; // assume this is a file that does not yet exist } @@ -957,7 +759,8 @@ export class WindowsManager implements IWindowsMainService, IWindowEventService vscodeWindow = this.instantiationService.createInstance(VSCodeWindow, { state: this.getNewWindowState(configuration), extensionDevelopmentPath: configuration.extensionDevelopmentPath, - allowFullscreen: this.lifecycleService.wasUpdated || (windowConfig && windowConfig.restoreFullscreen) + allowFullscreen: this.lifecycleService.wasUpdated || (windowConfig && windowConfig.restoreFullscreen), + titleBarStyle: windowConfig ? windowConfig.titleBarStyle : void 0 }); WindowsManager.WINDOWS.push(vscodeWindow); @@ -1360,4 +1163,22 @@ export class WindowsManager implements IWindowsMainService, IWindowEventService return pathA === pathB; } + + toggleMenuBar(windowId: number): void { + // Update in settings + const menuBarHidden = this.storageService.getItem(VSCodeWindow.menuBarHiddenKey, false); + const newMenuBarHidden = !menuBarHidden; + this.storageService.setItem(VSCodeWindow.menuBarHiddenKey, newMenuBarHidden); + + // Update across windows + WindowsManager.WINDOWS.forEach(w => w.setMenuBarVisibility(!newMenuBarHidden)); + + // Inform user if menu bar is now hidden + if (newMenuBarHidden) { + const vscodeWindow = this.getWindowById(windowId); + if (vscodeWindow) { + vscodeWindow.send('vscode:showInfoMessage', nls.localize('hiddenMenuBar', "You can still access the menu bar by pressing the **Alt** key.")); + } + } + } } diff --git a/src/vs/editor/browser/standalone/media/standalone-tokens.css b/src/vs/editor/browser/standalone/media/standalone-tokens.css index 7e188cb1f5a..83f7697e7f9 100644 --- a/src/vs/editor/browser/standalone/media/standalone-tokens.css +++ b/src/vs/editor/browser/standalone/media/standalone-tokens.css @@ -460,7 +460,7 @@ /* -------------------------------- Begin vs-dark tokens -------------------------------- */ .monaco-editor.vs-dark .token { color: #D4D4D4; } -.monaco-editor.vs-dark .token.whitespace { color: rgba(227, 228, 226, 0.16) !important; } +.monaco-editor.vs-dark .token.vs-whitespace { color: rgba(227, 228, 226, 0.16) !important; } .monaco-editor.vs-dark .token.builtin.function { color: #569CD6; } diff --git a/src/vs/editor/browser/standalone/simpleServices.ts b/src/vs/editor/browser/standalone/simpleServices.ts index 6dead3a8db9..16c4c979613 100644 --- a/src/vs/editor/browser/standalone/simpleServices.ts +++ b/src/vs/editor/browser/standalone/simpleServices.ts @@ -6,8 +6,9 @@ import { Schemas } from 'vs/base/common/network'; import Severity from 'vs/base/common/severity'; +import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, getConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, getConfigurationValue, IConfigurationKeys } from 'vs/platform/configuration/common/configuration'; import { IEditor, IEditorInput, IEditorOptions, IEditorService, IResourceInput, ITextEditorModel, Position } from 'vs/platform/editor/common/editor'; import { AbstractExtensionService, ActivatedExtension } from 'vs/platform/extensions/common/abstractExtensionService'; import { IExtensionDescription, IExtensionService } from 'vs/platform/extensions/common/extensions'; @@ -25,6 +26,8 @@ import { getDefaultValues as getDefaultConfiguration } from 'vs/platform/configu import { CommandService } from 'vs/platform/commands/common/commandService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; +import { ITextModelResolverService, ITextModelContentProvider } from 'vs/platform/textmodelResolver/common/resolver'; +import { IDisposable } from 'vs/base/common/lifecycle'; export class SimpleEditor implements IEditor { @@ -159,13 +162,23 @@ export class SimpleEditorService implements IEditorService { return model; } +} - public resolveEditorModel(typedData: IResourceInput, refresh?: boolean): TPromise { +export class SimpleEditorModelResolverService implements ITextModelResolverService { + public _serviceBrand: any; + + private editor: SimpleEditor; + + public setEditor(editor: editorCommon.IEditor): void { + this.editor = new SimpleEditor(editor); + } + + public resolve(resource: URI): TPromise { let model: editorCommon.IModel; model = this.editor.withTypedEditor( - (editor) => this.findModel(editor, typedData), - (diffEditor) => this.findModel(diffEditor.getOriginalEditor(), typedData) || this.findModel(diffEditor.getModifiedEditor(), typedData) + (editor) => this.findModel(editor, resource), + (diffEditor) => this.findModel(diffEditor.getOriginalEditor(), resource) || this.findModel(diffEditor.getModifiedEditor(), resource) ); if (!model) { @@ -174,6 +187,21 @@ export class SimpleEditorService implements IEditorService { return TPromise.as(new SimpleModel(model)); } + + public registerTextModelContentProvider(scheme: string, provider: ITextModelContentProvider): IDisposable { + return { + dispose: function () { /* no op */ } + }; + } + + private findModel(editor: editorCommon.ICommonCodeEditor, resource: URI): editorCommon.IModel { + let model = editor.getModel(); + if (model.uri.toString() !== resource.toString()) { + return null; + } + + return model; + } } export class SimpleProgressService implements IProgressService { @@ -362,4 +390,8 @@ export class SimpleConfigurationService implements IConfigurationService { user: getConfigurationValue(this.getConfiguration(), key) }; } + + public keys(): IConfigurationKeys { + return { default: [], user: [] }; + } } diff --git a/src/vs/editor/browser/standalone/standaloneEditor.ts b/src/vs/editor/browser/standalone/standaloneEditor.ts index 4ee7a7879e8..32e25f36ab7 100644 --- a/src/vs/editor/browser/standalone/standaloneEditor.ts +++ b/src/vs/editor/browser/standalone/standaloneEditor.ts @@ -17,7 +17,7 @@ import { OpenerService } from 'vs/platform/opener/browser/openerService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IModel } from 'vs/editor/common/editorCommon'; import { Colorizer, IColorizerElementOptions, IColorizerOptions } from 'vs/editor/browser/standalone/colorizer'; -import { SimpleEditorService } from 'vs/editor/browser/standalone/simpleServices'; +import { SimpleEditorService, SimpleEditorModelResolverService } from 'vs/editor/browser/standalone/simpleServices'; import * as modes from 'vs/editor/common/modes'; import { IWebWorkerOptions, MonacoWebWorker, createWebWorker as actualCreateWebWorker } from 'vs/editor/common/services/webWorker'; import { IMarkerData } from 'vs/platform/markers/common/markers'; @@ -30,6 +30,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; /** * @internal @@ -48,6 +49,12 @@ function withAllStandaloneServices(domElement: H services.set(IEditorService, simpleEditorService); } + let simpleEditorModelResolverService: SimpleEditorModelResolverService = null; + if (!services.has(ITextModelResolverService)) { + simpleEditorModelResolverService = new SimpleEditorModelResolverService(); + services.set(ITextModelResolverService, simpleEditorModelResolverService); + } + if (!services.has(IOpenerService)) { services.set(IOpenerService, new OpenerService(services.get(IEditorService), services.get(ICommandService))); } @@ -58,6 +65,10 @@ function withAllStandaloneServices(domElement: H simpleEditorService.setEditor(result); } + if (simpleEditorModelResolverService) { + simpleEditorModelResolverService.setEditor(result); + } + return result; } diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index 55c0db61e71..5865396fef2 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -154,7 +154,7 @@ export class ViewContentWidgets extends ViewPart { this._widgets[widget.getId()] = widgetData; let domNode = widget.getDomNode(); - domNode.style.position = this._context.configuration.editor.viewInfo.fixedOverflowWidgets ? 'fixed' : 'absolute'; + domNode.style.position = (this._context.configuration.editor.viewInfo.fixedOverflowWidgets && widget.allowEditorOverflow) ? 'fixed' : 'absolute'; StyleMutator.setMaxWidth(domNode, this._contentWidth); StyleMutator.setVisibility(domNode, 'hidden'); domNode.setAttribute('widgetId', widget.getId()); diff --git a/src/vs/editor/browser/widget/media/tokens.css b/src/vs/editor/browser/widget/media/tokens.css index 8c92eb952f9..eee8ea2d1aa 100644 --- a/src/vs/editor/browser/widget/media/tokens.css +++ b/src/vs/editor/browser/widget/media/tokens.css @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-editor .token.whitespace { +.monaco-editor .token.vs-whitespace { display:inline-block; } .monaco-editor.hc-black .token { @@ -11,21 +11,21 @@ } .monaco-editor.vs .token { color: #000000; } -.monaco-editor.vs .token.whitespace { color: rgba(51, 51, 51, 0.2) !important; } +.monaco-editor.vs .token.vs-whitespace { color: rgba(51, 51, 51, 0.2) !important; } .monaco-editor.vs .token.info-token { color: #316bcd; } .monaco-editor.vs .token.warn-token { color: #cd9731; } .monaco-editor.vs .token.error-token { color: #cd3131; } .monaco-editor.vs .token.debug-token { color: purple; } .monaco-editor.vs-dark .token { color: #D4D4D4; } -.monaco-editor.vs-dark .token.whitespace { color: rgba(227, 228, 226, 0.16) !important; } +.monaco-editor.vs-dark .token.vs-whitespace { color: rgba(227, 228, 226, 0.16) !important; } .monaco-editor.vs-dark .token.info-token { color: #6796e6; } .monaco-editor.vs-dark .token.warn-token { color: #cd9731; } .monaco-editor.vs-dark .token.error-token { color: #f44747; } .monaco-editor.vs-dark .token.debug-token { color: #b267e6; } .monaco-editor.hc-black .token { color: #FFFFFF; } -.monaco-editor.hc-black .token.whitespace { color: rgba(227, 228, 226, 0.16) !important; } +.monaco-editor.hc-black .token.vs-whitespace{ color: rgba(227, 228, 226, 0.16) !important; } .monaco-editor.hc-black .token.info-token { color: #6796e6; } .monaco-editor.hc-black .token.warn-token { color: #008000; } .monaco-editor.hc-black .token.error-token { color: #FF0000; } diff --git a/src/vs/editor/common/commands/shiftCommand.ts b/src/vs/editor/common/commands/shiftCommand.ts index bdd732545ab..13d3886b888 100644 --- a/src/vs/editor/common/commands/shiftCommand.ts +++ b/src/vs/editor/common/commands/shiftCommand.ts @@ -5,7 +5,7 @@ 'use strict'; import * as strings from 'vs/base/common/strings'; -import { CursorMoveHelper } from 'vs/editor/common/controller/cursorMoveHelper'; +import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { ICommand, ICursorStateComputerData, IEditOperationBuilder, ITokenizedModel } from 'vs/editor/common/editorCommon'; @@ -22,9 +22,9 @@ export class ShiftCommand implements ICommand { public static unshiftIndentCount(line: string, column: number, tabSize: number): number { // Determine the visible column where the content starts - let contentStartVisibleColumn = CursorMoveHelper.visibleColumnFromColumn2(line, column, tabSize); + let contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(line, column, tabSize); - let desiredTabStop = CursorMoveHelper.prevTabColumn(contentStartVisibleColumn, tabSize); + let desiredTabStop = CursorColumns.prevTabStop(contentStartVisibleColumn, tabSize); // The `desiredTabStop` is a multiple of `tabSize` => determine the number of indents return desiredTabStop / tabSize; @@ -32,9 +32,9 @@ export class ShiftCommand implements ICommand { public static shiftIndentCount(line: string, column: number, tabSize: number): number { // Determine the visible column where the content starts - let contentStartVisibleColumn = CursorMoveHelper.visibleColumnFromColumn2(line, column, tabSize); + let contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(line, column, tabSize); - let desiredTabStop = CursorMoveHelper.nextTabColumn(contentStartVisibleColumn, tabSize); + let desiredTabStop = CursorColumns.nextTabStop(contentStartVisibleColumn, tabSize); // The `desiredTabStop` is a multiple of `tabSize` => determine the number of indents return desiredTabStop / tabSize; @@ -97,7 +97,7 @@ export class ShiftCommand implements ICommand { } if (lineNumber > 1) { - let contentStartVisibleColumn = CursorMoveHelper.visibleColumnFromColumn2(lineText, indentationEndIndex + 1, tabSize); + let contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(lineText, indentationEndIndex + 1, tabSize); if (contentStartVisibleColumn % tabSize !== 0) { // The current line is "miss-aligned", so let's see if this is expected... // This can only happen when it has trailing commas in the indent diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index 48833c7ed4d..9c28ccd9211 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -15,7 +15,7 @@ import { ContextKeyExpr, IContextKey, IContextKeyServiceTarget, IContextKeyServi import { CommonEditorConfiguration } from 'vs/editor/common/config/commonEditorConfig'; import { DefaultConfig } from 'vs/editor/common/config/defaultConfig'; import { Cursor } from 'vs/editor/common/controller/cursor'; -import { CursorMoveHelper } from 'vs/editor/common/controller/cursorMoveHelper'; +import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; import { IViewModelHelper } from 'vs/editor/common/controller/oneCursor'; import { EditorState } from 'vs/editor/common/core/editorState'; import { Position } from 'vs/editor/common/core/position'; @@ -229,7 +229,7 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom let position = this.model.validatePosition(rawPosition); let tabSize = this.model.getOptions().tabSize; - return CursorMoveHelper.visibleColumnFromColumn(this.model, position.lineNumber, position.column, tabSize) + 1; + return CursorColumns.visibleColumnFromColumn(this.model.getLineContent(position.lineNumber), position.column, tabSize) + 1; } public getPosition(): Position { @@ -755,14 +755,11 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom convertViewSelectionToModelSelection: (viewSelection: editorCommon.ISelection) => { return this.viewModel.convertViewSelectionToModelSelection(viewSelection); }, - convertViewRangeToModelRange: (viewRange: Range) => { - return this.viewModel.convertViewRangeToModelRange(viewRange); + validateViewPosition: (viewPosition: Position, modelPosition: Position): Position => { + return this.viewModel.validateViewPosition(viewPosition.lineNumber, viewPosition.column, modelPosition); }, - validateViewPosition: (viewLineNumber: number, viewColumn: number, modelPosition: Position) => { - return this.viewModel.validateViewPosition(viewLineNumber, viewColumn, modelPosition); - }, - validateViewRange: (viewStartLineNumber: number, viewStartColumn: number, viewEndLineNumber: number, viewEndColumn: number, modelRange: Range) => { - return this.viewModel.validateViewRange(viewStartLineNumber, viewStartColumn, viewEndLineNumber, viewEndColumn, modelRange); + validateViewRange: (viewRange: Range, modelRange: Range): Range => { + return this.viewModel.validateViewRange(viewRange.startLineNumber, viewRange.startColumn, viewRange.endLineNumber, viewRange.endColumn, modelRange); } }; diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 569a9a272d3..c7424ed3cde 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -11,13 +11,17 @@ import { EventEmitter } from 'vs/base/common/eventEmitter'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; import { CursorCollection, ICursorCollectionState } from 'vs/editor/common/controller/cursorCollection'; -import { WordNavigationType, IOneCursorOperationContext, IPostOperationRunnable, IViewModelHelper, OneCursor, OneCursorOp } from 'vs/editor/common/controller/oneCursor'; +import { IOneCursorOperationContext, IViewModelHelper, OneCursor, OneCursorOp } from 'vs/editor/common/controller/oneCursor'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection, SelectionDirection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { IColumnSelectResult } from 'vs/editor/common/controller/cursorMoveHelper'; +import { CursorColumns, EditOperationResult } from 'vs/editor/common/controller/cursorCommon'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; +import { WordOperations, WordNavigationType } from 'vs/editor/common/controller/cursorWordOperations'; +import { ColumnSelection, IColumnSelectResult } from 'vs/editor/common/controller/cursorColumnSelection'; +import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; +import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; export interface ITypingListener { (): void; @@ -43,7 +47,6 @@ interface IMultipleCursorOperationContext { isCursorUndo: boolean; executeCommands: editorCommon.ICommand[]; isAutoWhitespaceCommand: boolean[]; - postOperationRunnables: IPostOperationRunnable[]; setColumnSelectToLineNumber: number; setColumnSelectToVisualColumn: number; } @@ -293,7 +296,6 @@ export class Cursor extends EventEmitter { isAutoWhitespaceCommand: [], hasExecutedCommands: false, isCursorUndo: false, - postOperationRunnables: [], shouldPushStackElementBefore: false, shouldPushStackElementAfter: false, setColumnSelectToLineNumber: 0, @@ -318,6 +320,10 @@ export class Cursor extends EventEmitter { try { var oldSelections = this.cursors.getSelections(); var oldViewSelections = this.cursors.getViewSelections(); + + // ensure valid state on all cursors + this.cursors.ensureValidState(); + var prevCursorsState = this.cursors.saveState(); var eventSource = source; @@ -412,35 +418,13 @@ export class Cursor extends EventEmitter { this._columnSelectToLineNumber = ctx.setColumnSelectToLineNumber; this._columnSelectToVisualColumn = ctx.setColumnSelectToVisualColumn; - ctx.hasExecutedCommands = this._internalExecuteCommands(ctx.executeCommands, ctx.isAutoWhitespaceCommand, ctx.postOperationRunnables) || ctx.hasExecutedCommands; + ctx.hasExecutedCommands = this._internalExecuteCommands(ctx.executeCommands, ctx.isAutoWhitespaceCommand) || ctx.hasExecutedCommands; ctx.executeCommands = []; if (ctx.shouldPushStackElementAfter) { this.model.pushStackElement(); ctx.shouldPushStackElementAfter = false; } - - var hasPostOperationRunnables = false; - for (var i = 0, len = ctx.postOperationRunnables.length; i < len; i++) { - if (ctx.postOperationRunnables[i]) { - hasPostOperationRunnables = true; - break; - } - } - - if (hasPostOperationRunnables) { - var postOperationRunnables = ctx.postOperationRunnables.slice(0); - ctx.postOperationRunnables = []; - - this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => { - if (postOperationRunnables[cursorIndex]) { - postOperationRunnables[cursorIndex](oneCtx); - } - return false; - }); - - this._interpretHandlerContext(ctx); - } } private _interpretCommandResult(cursorState: Selection[]): boolean { @@ -607,7 +591,7 @@ export class Cursor extends EventEmitter { return loserCursorsMap; } - private _collapseDeleteCommands(rawCmds: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[], postOperationRunnables: IPostOperationRunnable[]): boolean { + private _collapseDeleteCommands(rawCmds: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[]): boolean { if (rawCmds.length === 1) { return; } @@ -632,7 +616,6 @@ export class Cursor extends EventEmitter { var cursors = commands.map((cmd, i) => { return { range: commands[i].getRange(), - postOperationRunnable: postOperationRunnables[i], order: i }; }); @@ -663,15 +646,15 @@ export class Cursor extends EventEmitter { } } - private _internalExecuteCommands(commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[], postOperationRunnables: IPostOperationRunnable[]): boolean { + private _internalExecuteCommands(commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[]): boolean { var ctx: IExecContext = { selectionStartMarkers: [], positionMarkers: [] }; - this._collapseDeleteCommands(commands, isAutoWhitespaceCommand, postOperationRunnables); + this._collapseDeleteCommands(commands, isAutoWhitespaceCommand); - var r = this._innerExecuteCommands(ctx, commands, isAutoWhitespaceCommand, postOperationRunnables); + var r = this._innerExecuteCommands(ctx, commands, isAutoWhitespaceCommand); for (var i = 0; i < ctx.selectionStartMarkers.length; i++) { this.model._removeMarker(ctx.selectionStartMarkers[i]); this.model._removeMarker(ctx.positionMarkers[i]); @@ -692,7 +675,7 @@ export class Cursor extends EventEmitter { return true; } - private _innerExecuteCommands(ctx: IExecContext, commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[], postOperationRunnables: IPostOperationRunnable[]): boolean { + private _innerExecuteCommands(ctx: IExecContext, commands: editorCommon.ICommand[], isAutoWhitespaceCommand: boolean[]): boolean { if (this.configuration.editor.readOnly) { return false; @@ -793,7 +776,6 @@ export class Cursor extends EventEmitter { // Remove losing cursors for (var i = 0; i < losingCursors.length; i++) { selectionsAfter.splice(losingCursors[i], 1); - postOperationRunnables.splice(losingCursors[i], 1); } return this._interpretCommandResult(selectionsAfter); @@ -1069,7 +1051,6 @@ export class Cursor extends EventEmitter { shouldRevealHorizontal: true, executeCommand: null, isAutoWhitespaceCommand: false, - postOperationRunnable: null, shouldPushStackElementBefore: false, shouldPushStackElementAfter: false }; @@ -1088,7 +1069,6 @@ export class Cursor extends EventEmitter { ctx.executeCommands[i] = context.executeCommand; ctx.isAutoWhitespaceCommand[i] = context.isAutoWhitespaceCommand; - ctx.postOperationRunnables[i] = context.postOperationRunnable; } return result; @@ -1123,51 +1103,63 @@ export class Cursor extends EventEmitter { if (!this._columnSelectToVisualColumn) { let primaryCursor = this.cursors.getAll()[0]; let primaryPos = primaryCursor.viewState.position; - return primaryCursor.getViewVisibleColumnFromColumn(primaryPos.lineNumber, primaryPos.column); + return CursorColumns.visibleColumnFromColumn2(primaryCursor.config, primaryCursor.viewModel, primaryPos); } return this._columnSelectToVisualColumn; } private _columnSelectMouse(ctx: IMultipleCursorOperationContext): boolean { - let cursors = this.cursors.getAll(); - let result = OneCursorOp.columnSelectMouse(cursors[0], ctx.eventData.position, ctx.eventData.viewPosition, ctx.eventData.mouseColumn - 1); + let primary = this.cursors.getAll()[0]; + + // validate `eventData` + let validatedPosition = primary.model.validatePosition(ctx.eventData.position); + let validatedViewPosition: Position; + if (ctx.eventData.viewPosition) { + validatedViewPosition = primary.validateViewPosition(ctx.eventData.viewPosition.lineNumber, ctx.eventData.viewPosition.column, validatedPosition); + } else { + validatedViewPosition = primary.convertModelPositionToViewPosition(validatedPosition.lineNumber, validatedPosition.column); + } + + let result = ColumnSelection.columnSelect(primary.config, primary.viewModel, primary.viewState.selection.getStartPosition(), validatedViewPosition.lineNumber, ctx.eventData.mouseColumn - 1); + let selections = result.viewSelections.map(viewSel => primary.convertViewSelectionToModelSelection(viewSel)); ctx.shouldRevealTarget = (result.reversed ? RevealTarget.TopMost : RevealTarget.BottomMost); ctx.shouldReveal = true; ctx.setColumnSelectToLineNumber = result.toLineNumber; ctx.setColumnSelectToVisualColumn = result.toVisualColumn; - this.cursors.setSelections(result.selections, result.viewSelections); + this.cursors.setSelections(selections, result.viewSelections); return true; } private _columnSelectOp(ctx: IMultipleCursorOperationContext, op: (cursor: OneCursor, toViewLineNumber: number, toViewVisualColumn: number) => IColumnSelectResult): boolean { let primary = this.cursors.getAll()[0]; let result = op(primary, this._getColumnSelectToLineNumber(), this._getColumnSelectToVisualColumn()); + let selections = result.viewSelections.map(viewSel => primary.convertViewSelectionToModelSelection(viewSel)); ctx.shouldRevealTarget = (result.reversed ? RevealTarget.TopMost : RevealTarget.BottomMost); ctx.shouldReveal = true; ctx.setColumnSelectToLineNumber = result.toLineNumber; ctx.setColumnSelectToVisualColumn = result.toVisualColumn; - this.cursors.setSelections(result.selections, result.viewSelections); + this.cursors.setSelections(selections, result.viewSelections); return true; } private _columnSelectLeft(ctx: IMultipleCursorOperationContext): boolean { - return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => OneCursorOp.columnSelectLeft(cursor, toViewLineNumber, toViewVisualColumn)); + return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => ColumnSelection.columnSelectLeft(cursor.config, cursor.viewModel, cursor.viewState, toViewLineNumber, toViewVisualColumn)); } private _columnSelectRight(ctx: IMultipleCursorOperationContext): boolean { - return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => OneCursorOp.columnSelectRight(cursor, toViewLineNumber, toViewVisualColumn)); + return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => ColumnSelection.columnSelectRight(cursor.config, cursor.viewModel, cursor.viewState, toViewLineNumber, toViewVisualColumn)); } private _columnSelectUp(isPaged: boolean, ctx: IMultipleCursorOperationContext): boolean { - return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => OneCursorOp.columnSelectUp(isPaged, cursor, toViewLineNumber, toViewVisualColumn)); + return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => ColumnSelection.columnSelectUp(cursor.config, cursor.viewModel, cursor.viewState, isPaged, toViewLineNumber, toViewVisualColumn)); } private _columnSelectDown(isPaged: boolean, ctx: IMultipleCursorOperationContext): boolean { - return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => OneCursorOp.columnSelectDown(isPaged, cursor, toViewLineNumber, toViewVisualColumn)); + return this._columnSelectOp(ctx, (cursor, toViewLineNumber, toViewVisualColumn) => ColumnSelection.columnSelectDown(cursor.config, cursor.viewModel, cursor.viewState, isPaged, toViewLineNumber, toViewVisualColumn)); } private _createCursor(ctx: IMultipleCursorOperationContext): boolean { @@ -1347,21 +1339,9 @@ export class Cursor extends EventEmitter { return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.expandLineSelection(oneCursor, oneCtx)); } - private _lineInsertBefore(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.lineInsertBefore(oneCursor, oneCtx)); - } - - private _lineInsertAfter(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.lineInsertAfter(oneCursor, oneCtx)); - } - - private _lineBreakInsert(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.lineBreakInsert(oneCursor, oneCtx)); - } - private _word(inSelectionMode: boolean, ctx: IMultipleCursorOperationContext): boolean { this.cursors.killSecondaryCursors(); - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.word(oneCursor, inSelectionMode, ctx.eventData.position, oneCtx)); + return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.word(oneCursor, inSelectionMode, oneCursor.validatePosition(ctx.eventData.position), oneCtx)); } private _lastCursorWord(ctx: IMultipleCursorOperationContext): boolean { @@ -1372,7 +1352,7 @@ export class Cursor extends EventEmitter { var lastAddedCursor = this.cursors.getLastAddedCursor(); this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => { if (oneCursor === lastAddedCursor) { - return OneCursorOp.word(oneCursor, true, ctx.eventData.position, oneCtx); + return OneCursorOp.word(oneCursor, true, oneCursor.validatePosition(ctx.eventData.position), oneCtx); } return false; }); @@ -1392,6 +1372,41 @@ export class Cursor extends EventEmitter { return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.cancelSelection(oneCursor, oneCtx)); } + // -------------------- START editing operations + + private _doApplyEdit(cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext, callable: (oneCursor: OneCursor, cursorIndex: number) => EditOperationResult): boolean { + let r = callable(oneCursor, cursorIndex); + if (r) { + oneCtx.executeCommand = r.command; + oneCtx.shouldPushStackElementBefore = r.shouldPushStackElementBefore; + oneCtx.shouldPushStackElementAfter = r.shouldPushStackElementAfter; + oneCtx.isAutoWhitespaceCommand = r.isAutoWhitespaceCommand; + oneCtx.shouldRevealHorizontal = r.shouldRevealHorizontal; + oneCtx.cursorPositionChangeReason = r.cursorPositionChangeReason; + } + return true; + } + + private _applyEditForAll(ctx: IMultipleCursorOperationContext, callable: (oneCursor: OneCursor, cursorIndex: number) => EditOperationResult): boolean { + return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => this._doApplyEdit(cursorIndex, oneCursor, oneCtx, callable), false, false); + } + + private _applyEditForAllSorted(ctx: IMultipleCursorOperationContext, callable: (oneCursor: OneCursor, cursorIndex: number) => EditOperationResult): boolean { + return this._invokeForAllSorted(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => this._doApplyEdit(cursorIndex, oneCursor, oneCtx, callable), false, false); + } + + private _lineInsertBefore(ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => TypeOperations.lineInsertBefore(cursor.config, cursor.model, cursor.modelState)); + } + + private _lineInsertAfter(ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => TypeOperations.lineInsertAfter(cursor.config, cursor.model, cursor.modelState)); + } + + private _lineBreakInsert(ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => TypeOperations.lineBreakInsert(cursor.config, cursor.model, cursor.modelState)); + } + private _type(ctx: IMultipleCursorOperationContext): boolean { var text = ctx.eventData.text; @@ -1413,7 +1428,7 @@ export class Cursor extends EventEmitter { // Here we must interpret each typed character individually, that's why we create a new context ctx.hasExecutedCommands = this._createAndInterpretHandlerCtx(ctx.eventSource, ctx.eventData, (charHandlerCtx: IMultipleCursorOperationContext) => { - this._invokeForAll(charHandlerCtx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.type(oneCursor, chr, oneCtx), false, false); + this._applyEditForAll(charHandlerCtx, (cursor) => TypeOperations.typeWithInterceptors(cursor.config, cursor.model, cursor.modelState, chr)); // The last typed character gets to win ctx.cursorPositionChangeReason = charHandlerCtx.cursorPositionChangeReason; @@ -1424,7 +1439,7 @@ export class Cursor extends EventEmitter { } } else { - this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.actualType(oneCursor, text, false, oneCtx)); + this._applyEditForAll(ctx, (cursor) => TypeOperations.typeWithoutInterceptors(cursor.config, cursor.model, cursor.modelState, text)); } return true; @@ -1433,31 +1448,86 @@ export class Cursor extends EventEmitter { private _replacePreviousChar(ctx: IMultipleCursorOperationContext): boolean { let text = ctx.eventData.text; let replaceCharCnt = ctx.eventData.replaceCharCnt; - return this._invokeForAll(ctx, (cursorIndex, oneCursor, oneCtx) => OneCursorOp.replacePreviousChar(oneCursor, text, replaceCharCnt, oneCtx), false, false); + return this._applyEditForAll(ctx, (cursor) => TypeOperations.replacePreviousChar(cursor.config, cursor.model, cursor.modelState, text, replaceCharCnt)); } private _tab(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.tab(oneCursor, oneCtx), false, false); + return this._applyEditForAll(ctx, (cursor) => TypeOperations.tab(cursor.config, cursor.model, cursor.modelState)); } private _indent(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.indent(oneCursor, oneCtx)); + return this._applyEditForAll(ctx, (cursor) => TypeOperations.indent(cursor.config, cursor.model, cursor.modelState)); } private _outdent(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.outdent(oneCursor, oneCtx)); + return this._applyEditForAll(ctx, (cursor) => TypeOperations.outdent(cursor.config, cursor.model, cursor.modelState)); + } + + private _distributePasteToCursors(ctx: IMultipleCursorOperationContext): string[] { + if (ctx.eventData.pasteOnNewLine) { + return null; + } + + var selections = this.cursors.getSelections(); + if (selections.length === 1) { + return null; + } + + for (var i = 0; i < selections.length; i++) { + if (selections[i].startLineNumber !== selections[i].endLineNumber) { + return null; + } + } + + var pastePieces = ctx.eventData.text.split(/\r\n|\r|\n/); + if (pastePieces.length !== selections.length) { + return null; + } + + return pastePieces; } private _paste(ctx: IMultipleCursorOperationContext): boolean { var distributedPaste = this._distributePasteToCursors(ctx); if (distributedPaste) { - return this._invokeForAllSorted(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.paste(oneCursor, distributedPaste[cursorIndex], false, oneCtx)); + return this._applyEditForAllSorted(ctx, (cursor, cursorIndex) => TypeOperations.paste(cursor.config, cursor.model, cursor.modelState, distributedPaste[cursorIndex], false)); } else { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.paste(oneCursor, ctx.eventData.text, ctx.eventData.pasteOnNewLine, oneCtx)); + return this._applyEditForAll(ctx, (cursor) => TypeOperations.paste(cursor.config, cursor.model, cursor.modelState, ctx.eventData.text, ctx.eventData.pasteOnNewLine)); } } + private _deleteLeft(ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => DeleteOperations.deleteLeft(cursor.config, cursor.model, cursor.modelState)); + } + + private _deleteWordLeft(whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType, ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => WordOperations.deleteWordLeft(cursor.config, cursor.model, cursor.modelState, whitespaceHeuristics, wordNavigationType)); + } + + private _deleteRight(ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => DeleteOperations.deleteRight(cursor.config, cursor.model, cursor.modelState)); + } + + private _deleteWordRight(whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType, ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => WordOperations.deleteWordRight(cursor.config, cursor.model, cursor.modelState, whitespaceHeuristics, wordNavigationType)); + } + + private _deleteAllLeft(ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => DeleteOperations.deleteAllLeft(cursor.config, cursor.model, cursor.modelState)); + } + + private _deleteAllRight(ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => DeleteOperations.deleteAllRight(cursor.config, cursor.model, cursor.modelState)); + } + + private _cut(ctx: IMultipleCursorOperationContext): boolean { + return this._applyEditForAll(ctx, (cursor) => DeleteOperations.cut(cursor.config, cursor.model, cursor.modelState, this.enableEmptySelectionClipboard)); + } + + // -------------------- END editing operations + + private _revealLine(ctx: IMultipleCursorOperationContext): boolean { const revealLineArg: editorCommon.RevealLineArguments = ctx.eventData; const lineNumber = revealLineArg.lineNumber + 1; @@ -1510,10 +1580,10 @@ export class Cursor extends EventEmitter { let noOfLines = editorScrollArg.value || 1; switch (editorScrollArg.by) { case editorCommon.EditorScrollByUnit.Page: - noOfLines = cursor.getPageSize() * noOfLines; + noOfLines = cursor.config.pageSize * noOfLines; break; case editorCommon.EditorScrollByUnit.HalfPage: - noOfLines = Math.round(cursor.getPageSize() / 2) * noOfLines; + noOfLines = Math.round(cursor.config.pageSize / 2) * noOfLines; break; } this.emitCursorScrollRequest((up ? -1 : 1) * noOfLines, !!editorScrollArg.revealCursor); @@ -1548,58 +1618,6 @@ export class Cursor extends EventEmitter { return this._editorScroll(ctx); } - private _distributePasteToCursors(ctx: IMultipleCursorOperationContext): string[] { - if (ctx.eventData.pasteOnNewLine) { - return null; - } - - var selections = this.cursors.getSelections(); - if (selections.length === 1) { - return null; - } - - for (var i = 0; i < selections.length; i++) { - if (selections[i].startLineNumber !== selections[i].endLineNumber) { - return null; - } - } - - var pastePieces = ctx.eventData.text.split(/\r\n|\r|\n/); - if (pastePieces.length !== selections.length) { - return null; - } - - return pastePieces; - } - - private _deleteLeft(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.deleteLeft(oneCursor, oneCtx), false, false); - } - - private _deleteWordLeft(whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType, ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.deleteWordLeft(oneCursor, whitespaceHeuristics, wordNavigationType, oneCtx), false, false); - } - - private _deleteRight(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.deleteRight(oneCursor, oneCtx), false, false); - } - - private _deleteWordRight(whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType, ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.deleteWordRight(oneCursor, whitespaceHeuristics, wordNavigationType, oneCtx), false, false); - } - - private _deleteAllLeft(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.deleteAllLeft(oneCursor, oneCtx), false, false); - } - - private _deleteAllRight(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.deleteAllRight(oneCursor, oneCtx), false, false); - } - - private _cut(ctx: IMultipleCursorOperationContext): boolean { - return this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => OneCursorOp.cut(oneCursor, this.enableEmptySelectionClipboard, oneCtx)); - } - private _undo(ctx: IMultipleCursorOperationContext): boolean { ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Undo; ctx.hasExecutedCommands = true; diff --git a/src/vs/editor/common/controller/cursorCollection.ts b/src/vs/editor/common/controller/cursorCollection.ts index 71870abb0e6..6671d58d51f 100644 --- a/src/vs/editor/common/controller/cursorCollection.ts +++ b/src/vs/editor/common/controller/cursorCollection.ts @@ -49,6 +49,13 @@ export class CursorCollection { this.killSecondaryCursors(); } + public ensureValidState(): void { + this.primaryCursor.ensureValidState(); + for (let i = 0, len = this.secondaryCursors.length; i < len; i++) { + this.secondaryCursors[i].ensureValidState(); + } + } + public saveState(): ICursorCollectionState { return { primary: this.primaryCursor.saveState(), diff --git a/src/vs/editor/common/controller/cursorColumnSelection.ts b/src/vs/editor/common/controller/cursorColumnSelection.ts new file mode 100644 index 00000000000..86510a1fa2c --- /dev/null +++ b/src/vs/editor/common/controller/cursorColumnSelection.ts @@ -0,0 +1,120 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { Selection } from 'vs/editor/common/core/selection'; +import { Position } from 'vs/editor/common/core/position'; +import { SingleCursorState, CursorColumns, CursorConfiguration, ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon'; + +export interface IColumnSelectResult { + viewSelections: Selection[]; + reversed: boolean; + toLineNumber: number; + toVisualColumn: number; +} + +export class ColumnSelection { + + private static _columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult { + let lineCount = Math.abs(toLineNumber - fromLineNumber) + 1; + let reversed = (fromLineNumber > toLineNumber); + let isRTL = (fromVisibleColumn > toVisibleColumn); + let isLTR = (fromVisibleColumn < toVisibleColumn); + + let result: Selection[] = []; + + // console.log(`fromVisibleColumn: ${fromVisibleColumn}, toVisibleColumn: ${toVisibleColumn}`); + + for (let i = 0; i < lineCount; i++) { + let lineNumber = fromLineNumber + (reversed ? -i : i); + + let startColumn = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, fromVisibleColumn); + let endColumn = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, toVisibleColumn); + let visibleStartColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, startColumn)); + let visibleEndColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, endColumn)); + + // console.log(`lineNumber: ${lineNumber}: visibleStartColumn: ${visibleStartColumn}, visibleEndColumn: ${visibleEndColumn}`); + + if (isLTR) { + if (visibleStartColumn > toVisibleColumn) { + continue; + } + if (visibleEndColumn < fromVisibleColumn) { + continue; + } + } + + if (isRTL) { + if (visibleEndColumn > fromVisibleColumn) { + continue; + } + if (visibleStartColumn < toVisibleColumn) { + continue; + } + } + + result.push(new Selection(lineNumber, startColumn, lineNumber, endColumn)); + } + + return { + viewSelections: result, + reversed: reversed, + toLineNumber: toLineNumber, + toVisualColumn: toVisibleColumn + }; + } + + public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromViewPosition: Position, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + let fromViewVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, fromViewPosition); + return ColumnSelection._columnSelect(config, model, fromViewPosition.lineNumber, fromViewVisibleColumn, toViewLineNumber, toViewVisualColumn); + } + + public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + if (toViewVisualColumn > 1) { + toViewVisualColumn--; + } + + return this.columnSelect(config, model, cursor.selection.getStartPosition(), toViewLineNumber, toViewVisualColumn); + } + + public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + let maxVisualViewColumn = 0; + let minViewLineNumber = Math.min(cursor.position.lineNumber, toViewLineNumber); + let maxViewLineNumber = Math.max(cursor.position.lineNumber, toViewLineNumber); + for (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) { + let lineMaxViewColumn = model.getLineMaxColumn(lineNumber); + let lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn)); + maxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn); + } + + if (toViewVisualColumn < maxVisualViewColumn) { + toViewVisualColumn++; + } + + return this.columnSelect(config, model, cursor.selection.getStartPosition(), toViewLineNumber, toViewVisualColumn); + } + + public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + let linesCount = isPaged ? config.pageSize : 1; + + toViewLineNumber -= linesCount; + if (toViewLineNumber < 1) { + toViewLineNumber = 1; + } + + return this.columnSelect(config, model, cursor.selection.getStartPosition(), toViewLineNumber, toViewVisualColumn); + } + + public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + let linesCount = isPaged ? config.pageSize : 1; + + toViewLineNumber += linesCount; + if (toViewLineNumber > model.getLineCount()) { + toViewLineNumber = model.getLineCount(); + } + + return this.columnSelect(config, model, cursor.selection.getStartPosition(), toViewLineNumber, toViewVisualColumn); + } +} diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts new file mode 100644 index 00000000000..ad62241d92d --- /dev/null +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -0,0 +1,347 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { Position } from 'vs/editor/common/core/position'; +import { CharCode } from 'vs/base/common/charCode'; +import * as strings from 'vs/base/common/strings'; +import { IModeConfiguration } from 'vs/editor/common/controller/oneCursor'; +import { ICommand, CursorChangeReason, IConfigurationChangedEvent, TextModelResolvedOptions, IConfiguration } from 'vs/editor/common/editorCommon'; +import { TextModel } from 'vs/editor/common/model/textModel'; +import { Selection } from 'vs/editor/common/core/selection'; +import { Range } from 'vs/editor/common/core/range'; + +export interface CharacterMap { + [char: string]: string; +} + +export class CursorConfiguration { + _cursorMoveConfigurationBrand: void; + + public readonly tabSize: number; + public readonly insertSpaces: boolean; + public readonly oneIndent: string; + public readonly pageSize: number; + public readonly useTabStops: boolean; + public readonly wordSeparators: string; + public readonly autoClosingBrackets: boolean; + public readonly autoClosingPairsOpen: CharacterMap; + public readonly autoClosingPairsClose: CharacterMap; + public readonly surroundingPairs: CharacterMap; + public readonly electricChars: { [key: string]: boolean; }; + + public static shouldRecreate(e: IConfigurationChangedEvent): boolean { + return ( + e.layoutInfo + || e.wordSeparators + || e.autoClosingBrackets + || e.useTabStops + ); + } + + constructor( + oneIndent: string, + modelOptions: TextModelResolvedOptions, + configuration: IConfiguration, + modeConfiguration: IModeConfiguration + ) { + let c = configuration.editor; + + this.tabSize = modelOptions.tabSize; + this.insertSpaces = modelOptions.insertSpaces; + this.oneIndent = oneIndent; + this.pageSize = Math.floor(c.layoutInfo.height / c.fontInfo.lineHeight) - 2; + this.useTabStops = c.useTabStops; + this.wordSeparators = c.wordSeparators; + this.autoClosingBrackets = c.autoClosingBrackets; + this.autoClosingPairsOpen = modeConfiguration.autoClosingPairsOpen; + this.autoClosingPairsClose = modeConfiguration.autoClosingPairsClose; + this.surroundingPairs = modeConfiguration.surroundingPairs; + this.electricChars = modeConfiguration.electricChars; + } + + public normalizeIndentation(str: string): string { + return TextModel.normalizeIndentation(str, this.tabSize, this.insertSpaces); + } +} + +/** + * Represents a simple model (either the model or the view model). + */ +export interface ICursorSimpleModel { + getLineCount(): number; + getLineContent(lineNumber: number): string; + getLineMinColumn(lineNumber: number): number; + getLineMaxColumn(lineNumber: number): number; + getLineFirstNonWhitespaceColumn(lineNumber: number): number; + getLineLastNonWhitespaceColumn(lineNumber: number): number; +} + +/** + * Represents the cursor state on either the model or on the view model. + */ +export class SingleCursorState { + _singleCursorStateBrand: void; + + // --- selection can start as a range (think double click and drag) + public readonly selectionStart: Range; + public readonly selectionStartLeftoverVisibleColumns: number; + public readonly position: Position; + public readonly leftoverVisibleColumns: number; + public readonly selection: Selection; + + constructor( + selectionStart: Range, + selectionStartLeftoverVisibleColumns: number, + position: Position, + leftoverVisibleColumns: number, + ) { + this.selectionStart = selectionStart; + this.selectionStartLeftoverVisibleColumns = selectionStartLeftoverVisibleColumns; + this.position = position; + this.leftoverVisibleColumns = leftoverVisibleColumns; + this.selection = SingleCursorState._computeSelection(this.selectionStart, this.position); + } + + public equals(other: SingleCursorState) { + return ( + this.selectionStartLeftoverVisibleColumns === other.selectionStartLeftoverVisibleColumns + && this.leftoverVisibleColumns === other.leftoverVisibleColumns + && this.position.equals(other.position) + && this.selectionStart.equalsRange(other.selectionStart) + ); + } + + public hasSelection(): boolean { + return (!this.selection.isEmpty() || !this.selectionStart.isEmpty()); + } + + public withSelectionStartLeftoverVisibleColumns(selectionStartLeftoverVisibleColumns: number): SingleCursorState { + return new SingleCursorState( + this.selectionStart, + selectionStartLeftoverVisibleColumns, + this.position, + this.leftoverVisibleColumns + ); + } + + public withSelectionStart(selectionStart: Range): SingleCursorState { + return new SingleCursorState( + selectionStart, + 0, + this.position, + this.leftoverVisibleColumns + ); + } + + public collapse(): SingleCursorState { + return new SingleCursorState( + new Range(this.position.lineNumber, this.position.column, this.position.lineNumber, this.position.column), + 0, + this.position, + 0 + ); + } + + public move(inSelectionMode: boolean, position: Position, leftoverVisibleColumns: number): SingleCursorState { + if (inSelectionMode) { + // move just position + return new SingleCursorState( + this.selectionStart, + this.selectionStartLeftoverVisibleColumns, + position, + leftoverVisibleColumns + ); + } else { + // move everything + return new SingleCursorState( + new Range(position.lineNumber, position.column, position.lineNumber, position.column), + leftoverVisibleColumns, + position, + leftoverVisibleColumns + ); + } + } + + private static _computeSelection(selectionStart: Range, position: Position): Selection { + let startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number; + if (selectionStart.isEmpty()) { + startLineNumber = selectionStart.startLineNumber; + startColumn = selectionStart.startColumn; + endLineNumber = position.lineNumber; + endColumn = position.column; + } else { + if (position.isBeforeOrEqual(selectionStart.getStartPosition())) { + startLineNumber = selectionStart.endLineNumber; + startColumn = selectionStart.endColumn; + endLineNumber = position.lineNumber; + endColumn = position.column; + } else { + startLineNumber = selectionStart.startLineNumber; + startColumn = selectionStart.startColumn; + endLineNumber = position.lineNumber; + endColumn = position.column; + } + } + return new Selection( + startLineNumber, + startColumn, + endLineNumber, + endColumn + ); + } +} + +export class EditOperationResult { + _editOperationBrand: void; + + readonly command: ICommand; + readonly shouldPushStackElementBefore: boolean; + readonly shouldPushStackElementAfter: boolean; + readonly isAutoWhitespaceCommand: boolean; + readonly shouldRevealHorizontal: boolean; + readonly cursorPositionChangeReason: CursorChangeReason; + + constructor( + command: ICommand, + opts: { + shouldPushStackElementBefore: boolean; + shouldPushStackElementAfter: boolean; + isAutoWhitespaceCommand?: boolean; + shouldRevealHorizontal?: boolean; + cursorPositionChangeReason?: CursorChangeReason; + } + ) { + this.command = command; + this.shouldPushStackElementBefore = opts.shouldPushStackElementBefore; + this.shouldPushStackElementAfter = opts.shouldPushStackElementAfter; + this.isAutoWhitespaceCommand = false; + this.shouldRevealHorizontal = true; + this.cursorPositionChangeReason = CursorChangeReason.NotSet; + + if (typeof opts.isAutoWhitespaceCommand !== 'undefined') { + this.isAutoWhitespaceCommand = opts.isAutoWhitespaceCommand; + } + if (typeof opts.shouldRevealHorizontal !== 'undefined') { + this.shouldRevealHorizontal = opts.shouldRevealHorizontal; + } + if (typeof opts.cursorPositionChangeReason !== 'undefined') { + this.cursorPositionChangeReason = opts.cursorPositionChangeReason; + } + } +} + +/** + * Common operations that work and make sense both on the model and on the view model. + */ +export class CursorColumns { + + public static isLowSurrogate(model: ICursorSimpleModel, lineNumber: number, charOffset: number): boolean { + let lineContent = model.getLineContent(lineNumber); + if (charOffset < 0 || charOffset >= lineContent.length) { + return false; + } + return strings.isLowSurrogate(lineContent.charCodeAt(charOffset)); + } + + public static isHighSurrogate(model: ICursorSimpleModel, lineNumber: number, charOffset: number): boolean { + let lineContent = model.getLineContent(lineNumber); + if (charOffset < 0 || charOffset >= lineContent.length) { + return false; + } + return strings.isHighSurrogate(lineContent.charCodeAt(charOffset)); + } + + public static isInsideSurrogatePair(model: ICursorSimpleModel, lineNumber: number, column: number): boolean { + return this.isHighSurrogate(model, lineNumber, column - 2); + } + + public static visibleColumnFromColumn(lineContent: string, column: number, tabSize: number): number { + let endOffset = lineContent.length; + if (endOffset > column - 1) { + endOffset = column - 1; + } + + let result = 0; + for (let i = 0; i < endOffset; i++) { + let charCode = lineContent.charCodeAt(i); + if (charCode === CharCode.Tab) { + result = this.nextTabStop(result, tabSize); + } else { + result = result + 1; + } + } + return result; + } + + public static visibleColumnFromColumn2(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): number { + return this.visibleColumnFromColumn(model.getLineContent(position.lineNumber), position.column, config.tabSize); + } + + public static columnFromVisibleColumn(lineContent: string, visibleColumn: number, tabSize: number): number { + if (visibleColumn <= 0) { + return 1; + } + + const lineLength = lineContent.length; + + let beforeVisibleColumn = 0; + for (let i = 0; i < lineLength; i++) { + let charCode = lineContent.charCodeAt(i); + + let afterVisibleColumn: number; + if (charCode === CharCode.Tab) { + afterVisibleColumn = this.nextTabStop(beforeVisibleColumn, tabSize); + } else { + afterVisibleColumn = beforeVisibleColumn + 1; + } + + if (afterVisibleColumn >= visibleColumn) { + let prevDelta = visibleColumn - beforeVisibleColumn; + let afterDelta = afterVisibleColumn - visibleColumn; + if (afterDelta < prevDelta) { + return i + 2; + } else { + return i + 1; + } + } + + beforeVisibleColumn = afterVisibleColumn; + } + + // walked the entire string + return lineLength + 1; + } + + public static columnFromVisibleColumn2(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, visibleColumn: number): number { + let result = this.columnFromVisibleColumn(model.getLineContent(lineNumber), visibleColumn, config.tabSize); + + let minColumn = model.getLineMinColumn(lineNumber); + if (result < minColumn) { + return minColumn; + } + + let maxColumn = model.getLineMaxColumn(lineNumber); + if (result > maxColumn) { + return maxColumn; + } + + return result; + } + + /** + * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns) + */ + public static nextTabStop(visibleColumn: number, tabSize: number): number { + return visibleColumn + tabSize - visibleColumn % tabSize; + } + + /** + * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns) + */ + public static prevTabStop(column: number, tabSize: number): number { + return column - 1 - (column - 1) % tabSize; + } +} diff --git a/src/vs/editor/common/controller/cursorDeleteOperations.ts b/src/vs/editor/common/controller/cursorDeleteOperations.ts new file mode 100644 index 00000000000..81a52b0e5b9 --- /dev/null +++ b/src/vs/editor/common/controller/cursorDeleteOperations.ts @@ -0,0 +1,257 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; +import { SingleCursorState, EditOperationResult, CursorColumns, CursorConfiguration, ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon'; +import { Range } from 'vs/editor/common/core/range'; +import { MoveOperations } from 'vs/editor/common/controller/cursorMoveOperations'; +import * as strings from 'vs/base/common/strings'; + +export class DeleteOperations { + + public static deleteRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + + let deleteSelection: Range = cursor.selection; + + if (deleteSelection.isEmpty()) { + let position = cursor.position; + let rightOfPosition = MoveOperations.right(config, model, position.lineNumber, position.column); + deleteSelection = new Range( + rightOfPosition.lineNumber, + rightOfPosition.column, + position.lineNumber, + position.column + ); + } + + if (deleteSelection.isEmpty()) { + // Probably at end of file => ignore + return null; + } + + let shouldPushStackElementBefore = false; + if (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) { + shouldPushStackElementBefore = true; + } + + return new EditOperationResult(new ReplaceCommand(deleteSelection, ''), { + shouldPushStackElementBefore: shouldPushStackElementBefore, + shouldPushStackElementAfter: false + }); + } + + public static deleteAllRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + let selection = cursor.selection; + + if (selection.isEmpty()) { + let position = cursor.position; + let lineNumber = position.lineNumber; + let column = position.column; + let maxColumn = model.getLineMaxColumn(lineNumber); + + if (column === maxColumn) { + // Ignore deleting at end of file + return null; + } + + let deleteSelection = new Range(lineNumber, column, lineNumber, maxColumn); + if (!deleteSelection.isEmpty()) { + return new EditOperationResult(new ReplaceCommand(deleteSelection, ''), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + } + + return this.deleteRight(config, model, cursor); + } + + public static autoClosingPairDelete(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + if (!config.autoClosingBrackets) { + return null; + } + + if (!cursor.selection.isEmpty()) { + return null; + } + + let position = cursor.position; + + let lineText = model.getLineContent(position.lineNumber); + let character = lineText[position.column - 2]; + + if (!config.autoClosingPairsOpen.hasOwnProperty(character)) { + return null; + } + + let afterCharacter = lineText[position.column - 1]; + let closeCharacter = config.autoClosingPairsOpen[character]; + + if (afterCharacter !== closeCharacter) { + return null; + } + + let deleteSelection = new Range( + position.lineNumber, + position.column - 1, + position.lineNumber, + position.column + 1 + ); + + return new EditOperationResult(new ReplaceCommand(deleteSelection, ''), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + + public static deleteLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + let r = this.autoClosingPairDelete(config, model, cursor); + if (r) { + // This was a case for an auto-closing pair delete + return r; + } + + let deleteSelection: Range = cursor.selection; + + if (deleteSelection.isEmpty()) { + let position = cursor.position; + + if (config.useTabStops && position.column > 1) { + let lineContent = model.getLineContent(position.lineNumber); + + let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent); + let lastIndentationColumn = ( + firstNonWhitespaceIndex === -1 + ? /* entire string is whitespace */lineContent.length + 1 + : firstNonWhitespaceIndex + 1 + ); + + if (position.column <= lastIndentationColumn) { + let fromVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, position); + let toVisibleColumn = CursorColumns.prevTabStop(fromVisibleColumn, config.tabSize); + let toColumn = CursorColumns.columnFromVisibleColumn2(config, model, position.lineNumber, toVisibleColumn); + deleteSelection = new Range(position.lineNumber, toColumn, position.lineNumber, position.column); + } else { + deleteSelection = new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column); + } + } else { + let leftOfPosition = MoveOperations.left(config, model, position.lineNumber, position.column); + deleteSelection = new Range( + leftOfPosition.lineNumber, + leftOfPosition.column, + position.lineNumber, + position.column + ); + } + } + + if (deleteSelection.isEmpty()) { + // Probably at beginning of file => ignore + return null; + } + + let shouldPushStackElementBefore = false; + if (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) { + shouldPushStackElementBefore = true; + } + + return new EditOperationResult(new ReplaceCommand(deleteSelection, ''), { + shouldPushStackElementBefore: shouldPushStackElementBefore, + shouldPushStackElementAfter: false + }); + } + + public static deleteAllLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + let r = this.autoClosingPairDelete(config, model, cursor); + if (r) { + // This was a case for an auto-closing pair delete + return r; + } + + let selection = cursor.selection; + + if (selection.isEmpty()) { + let position = cursor.position; + let lineNumber = position.lineNumber; + let column = position.column; + + if (column === 1) { + // Ignore deleting at beginning of line + return null; + } + + let deleteSelection = new Range(lineNumber, 1, lineNumber, column); + if (!deleteSelection.isEmpty()) { + return new EditOperationResult(new ReplaceCommand(deleteSelection, ''), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + } + + return this.deleteLeft(config, model, cursor); + } + + public static cut(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, enableEmptySelectionClipboard: boolean): EditOperationResult { + let selection = cursor.selection; + + if (selection.isEmpty()) { + if (enableEmptySelectionClipboard) { + // This is a full line cut + + let position = cursor.position; + + let startLineNumber: number, + startColumn: number, + endLineNumber: number, + endColumn: number; + + if (position.lineNumber < model.getLineCount()) { + // Cutting a line in the middle of the model + startLineNumber = position.lineNumber; + startColumn = 1; + endLineNumber = position.lineNumber + 1; + endColumn = 1; + } else if (position.lineNumber > 1) { + // Cutting the last line & there are more than 1 lines in the model + startLineNumber = position.lineNumber - 1; + startColumn = model.getLineMaxColumn(position.lineNumber - 1); + endLineNumber = position.lineNumber; + endColumn = model.getLineMaxColumn(position.lineNumber); + } else { + // Cutting the single line that the model contains + startLineNumber = position.lineNumber; + startColumn = 1; + endLineNumber = position.lineNumber; + endColumn = model.getLineMaxColumn(position.lineNumber); + } + + let deleteSelection = new Range( + startLineNumber, + startColumn, + endLineNumber, + endColumn + ); + + if (!deleteSelection.isEmpty()) { + return new EditOperationResult(new ReplaceCommand(deleteSelection, ''), { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: true + }); + } else { + return null; + } + } else { + // Cannot cut empty selection + return null; + } + } else { + // Delete left or right, they will both result in the selection being deleted + return this.deleteRight(config, model, cursor); + } + } + +} \ No newline at end of file diff --git a/src/vs/editor/common/controller/cursorMoveHelper.ts b/src/vs/editor/common/controller/cursorMoveHelper.ts index d0b99bc11f9..db5df0ed28e 100644 --- a/src/vs/editor/common/controller/cursorMoveHelper.ts +++ b/src/vs/editor/common/controller/cursorMoveHelper.ts @@ -4,305 +4,11 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { Selection } from 'vs/editor/common/core/selection'; -import { CharCode } from 'vs/base/common/charCode'; -import * as strings from 'vs/base/common/strings'; - -export class CursorMoveConfiguration { - _cursorMoveConfigurationBrand: void; - - public readonly tabSize: number; - public readonly pageSize: number; - - constructor( - tabSize: number, - pageSize: number - ) { - this.tabSize = tabSize; - this.pageSize = pageSize; - } -} - -export interface ICursorMoveHelperModel { - getLineCount(): number; - getLineContent(lineNumber: number): string; - getLineMinColumn(lineNumber: number): number; - getLineMaxColumn(lineNumber: number): number; - getLineFirstNonWhitespaceColumn(lineNumber: number): number; - getLineLastNonWhitespaceColumn(lineNumber: number): number; -} - -export class CursorMoveResult { - _cursorMoveResultBrand: void; - - public readonly lineNumber: number; - public readonly column: number; - public readonly leftoverVisibleColumns: number; - - constructor(lineNumber: number, column: number, leftoverVisibleColumns: number) { - this.lineNumber = lineNumber; - this.column = column; - this.leftoverVisibleColumns = leftoverVisibleColumns; - } -} - -/** - * Common operations that work and make sense both on the model and on the view model. - */ -export class CursorMove { - - private static _isLowSurrogate(model: ICursorMoveHelperModel, lineNumber: number, charOffset: number): boolean { - let lineContent = model.getLineContent(lineNumber); - if (charOffset < 0 || charOffset >= lineContent.length) { - return false; - } - return strings.isLowSurrogate(lineContent.charCodeAt(charOffset)); - } - - private static _isHighSurrogate(model: ICursorMoveHelperModel, lineNumber: number, charOffset: number): boolean { - let lineContent = model.getLineContent(lineNumber); - if (charOffset < 0 || charOffset >= lineContent.length) { - return false; - } - return strings.isHighSurrogate(lineContent.charCodeAt(charOffset)); - } - - private static _isInsideSurrogatePair(model: ICursorMoveHelperModel, lineNumber: number, column: number): boolean { - return this._isHighSurrogate(model, lineNumber, column - 2); - } - - public static left(config: CursorMoveConfiguration, model: ICursorMoveHelperModel, lineNumber: number, column: number): CursorMoveResult { - - if (column > model.getLineMinColumn(lineNumber)) { - if (this._isLowSurrogate(model, lineNumber, column - 2)) { - // character before column is a low surrogate - column = column - 2; - } else { - column = column - 1; - } - } else if (lineNumber > 1) { - lineNumber = lineNumber - 1; - column = model.getLineMaxColumn(lineNumber); - } - - return new CursorMoveResult(lineNumber, column, 0); - } - - public static right(config: CursorMoveConfiguration, model: ICursorMoveHelperModel, lineNumber: number, column: number): CursorMoveResult { - - if (column < model.getLineMaxColumn(lineNumber)) { - if (this._isHighSurrogate(model, lineNumber, column - 1)) { - // character after column is a high surrogate - column = column + 2; - } else { - column = column + 1; - } - } else if (lineNumber < model.getLineCount()) { - lineNumber = lineNumber + 1; - column = model.getLineMinColumn(lineNumber); - } - - return new CursorMoveResult(lineNumber, column, 0); - } - - public static up(config: CursorMoveConfiguration, model: ICursorMoveHelperModel, lineNumber: number, column: number, leftoverVisibleColumns: number, count: number, allowMoveOnFirstLine: boolean): CursorMoveResult { - const currentVisibleColumn = this.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize) + leftoverVisibleColumns; - - lineNumber = lineNumber - count; - if (lineNumber < 1) { - lineNumber = 1; - if (allowMoveOnFirstLine) { - column = model.getLineMinColumn(lineNumber); - } else { - column = Math.min(model.getLineMaxColumn(lineNumber), column); - if (this._isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } - } - } else { - column = this.columnFromVisibleColumn(config, model, lineNumber, currentVisibleColumn); - if (this._isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } - } - - leftoverVisibleColumns = currentVisibleColumn - this.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize); - - return new CursorMoveResult(lineNumber, column, leftoverVisibleColumns); - } - - public static down(config: CursorMoveConfiguration, model: ICursorMoveHelperModel, lineNumber: number, column: number, leftoverVisibleColumns: number, count: number, allowMoveOnLastLine: boolean): CursorMoveResult { - const currentVisibleColumn = this.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize) + leftoverVisibleColumns; - - lineNumber = lineNumber + count; - var lineCount = model.getLineCount(); - if (lineNumber > lineCount) { - lineNumber = lineCount; - if (allowMoveOnLastLine) { - column = model.getLineMaxColumn(lineNumber); - } else { - column = Math.min(model.getLineMaxColumn(lineNumber), column); - if (this._isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } - } - } else { - column = this.columnFromVisibleColumn(config, model, lineNumber, currentVisibleColumn); - if (this._isInsideSurrogatePair(model, lineNumber, column)) { - column = column - 1; - } - } - - leftoverVisibleColumns = currentVisibleColumn - this.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize); - - return new CursorMoveResult(lineNumber, column, leftoverVisibleColumns); - } - - public static visibleColumnFromColumn(lineContent: string, column: number, tabSize: number): number { - let endOffset = lineContent.length; - if (endOffset > column - 1) { - endOffset = column - 1; - } - - let result = 0; - for (let i = 0; i < endOffset; i++) { - let charCode = lineContent.charCodeAt(i); - if (charCode === CharCode.Tab) { - result = this.nextTabStop(result, tabSize); - } else { - result = result + 1; - } - } - return result; - } - - private static _columnFromVisibleColumn(lineContent: string, visibleColumn: number, tabSize: number): number { - if (visibleColumn <= 0) { - return 1; - } - - const lineLength = lineContent.length; - - let beforeVisibleColumn = 0; - for (let i = 0; i < lineLength; i++) { - let charCode = lineContent.charCodeAt(i); - - let afterVisibleColumn: number; - if (charCode === CharCode.Tab) { - afterVisibleColumn = this.nextTabStop(beforeVisibleColumn, tabSize); - } else { - afterVisibleColumn = beforeVisibleColumn + 1; - } - - if (afterVisibleColumn >= visibleColumn) { - let prevDelta = visibleColumn - beforeVisibleColumn; - let afterDelta = afterVisibleColumn - visibleColumn; - if (afterDelta < prevDelta) { - return i + 2; - } else { - return i + 1; - } - } - - beforeVisibleColumn = afterVisibleColumn; - } - - // walked the entire string - return lineLength + 1; - } - - public static columnFromVisibleColumn(config: CursorMoveConfiguration, model: ICursorMoveHelperModel, lineNumber: number, visibleColumn: number): number { - let result = this._columnFromVisibleColumn(model.getLineContent(lineNumber), visibleColumn, config.tabSize); - - let minColumn = model.getLineMinColumn(lineNumber); - if (result < minColumn) { - return minColumn; - } - - let maxColumn = model.getLineMaxColumn(lineNumber); - if (result > maxColumn) { - return maxColumn; - } - - return result; - } - - /** - * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns) - */ - public static nextTabStop(visibleColumn: number, tabSize: number): number { - return visibleColumn + tabSize - visibleColumn % tabSize; - } -} - - -export interface IViewColumnSelectResult { - viewSelections: Selection[]; - reversed: boolean; -} -export interface IColumnSelectResult extends IViewColumnSelectResult { - selections: Selection[]; - toLineNumber: number; - toVisualColumn: number; -} - +import { ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon'; export class CursorMoveHelper { - private readonly _config: CursorMoveConfiguration; - - constructor(config: CursorMoveConfiguration) { - this._config = config; - } - - public columnSelect(model: ICursorMoveHelperModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IViewColumnSelectResult { - let lineCount = Math.abs(toLineNumber - fromLineNumber) + 1; - let reversed = (fromLineNumber > toLineNumber); - let isRTL = (fromVisibleColumn > toVisibleColumn); - let isLTR = (fromVisibleColumn < toVisibleColumn); - - let result: Selection[] = []; - - // console.log(`fromVisibleColumn: ${fromVisibleColumn}, toVisibleColumn: ${toVisibleColumn}`); - - for (let i = 0; i < lineCount; i++) { - let lineNumber = fromLineNumber + (reversed ? -i : i); - - let startColumn = this.columnFromVisibleColumn(model, lineNumber, fromVisibleColumn); - let endColumn = this.columnFromVisibleColumn(model, lineNumber, toVisibleColumn); - let visibleStartColumn = this.visibleColumnFromColumn(model, lineNumber, startColumn); - let visibleEndColumn = this.visibleColumnFromColumn(model, lineNumber, endColumn); - - // console.log(`lineNumber: ${lineNumber}: visibleStartColumn: ${visibleStartColumn}, visibleEndColumn: ${visibleEndColumn}`); - - if (isLTR) { - if (visibleStartColumn > toVisibleColumn) { - continue; - } - if (visibleEndColumn < fromVisibleColumn) { - continue; - } - } - - if (isRTL) { - if (visibleEndColumn > fromVisibleColumn) { - continue; - } - if (visibleStartColumn < toVisibleColumn) { - continue; - } - } - - result.push(new Selection(lineNumber, startColumn, lineNumber, endColumn)); - } - - return { - viewSelections: result, - reversed: reversed - }; - } - - public getColumnAtBeginningOfLine(model: ICursorMoveHelperModel, lineNumber: number, column: number): number { + public static getColumnAtBeginningOfLine(model: ICursorSimpleModel, lineNumber: number, column: number): number { var firstNonBlankColumn = model.getLineFirstNonWhitespaceColumn(lineNumber) || 1; var minColumn = model.getLineMinColumn(lineNumber); @@ -315,7 +21,7 @@ export class CursorMoveHelper { return column; } - public getColumnAtEndOfLine(model: ICursorMoveHelperModel, lineNumber: number, column: number): number { + public static getColumnAtEndOfLine(model: ICursorSimpleModel, lineNumber: number, column: number): number { var maxColumn = model.getLineMaxColumn(lineNumber); var lastNonBlankColumn = model.getLineLastNonWhitespaceColumn(lineNumber) || maxColumn; @@ -328,33 +34,4 @@ export class CursorMoveHelper { return column; } - public visibleColumnFromColumn(model: ICursorMoveHelperModel, lineNumber: number, column: number): number { - return CursorMoveHelper.visibleColumnFromColumn(model, lineNumber, column, this._config.tabSize); - } - - public static visibleColumnFromColumn(model: ICursorMoveHelperModel, lineNumber: number, column: number, tabSize: number): number { - return CursorMoveHelper.visibleColumnFromColumn2(model.getLineContent(lineNumber), column, tabSize); - } - - public static visibleColumnFromColumn2(line: string, column: number, tabSize: number): number { - return CursorMove.visibleColumnFromColumn(line, column, tabSize); - } - - public columnFromVisibleColumn(model: ICursorMoveHelperModel, lineNumber: number, visibleColumn: number): number { - return CursorMove.columnFromVisibleColumn(this._config, model, lineNumber, visibleColumn); - } - - /** - * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns) - */ - public static nextTabColumn(column: number, tabSize: number): number { - return CursorMove.nextTabStop(column, tabSize); - } - - /** - * ATTENTION: This works with 0-based columns (as oposed to the regular 1-based columns) - */ - public static prevTabColumn(column: number, tabSize: number): number { - return column - 1 - (column - 1) % tabSize; - } -} \ No newline at end of file +} diff --git a/src/vs/editor/common/controller/cursorMoveOperations.ts b/src/vs/editor/common/controller/cursorMoveOperations.ts new file mode 100644 index 00000000000..9d9861a1915 --- /dev/null +++ b/src/vs/editor/common/controller/cursorMoveOperations.ts @@ -0,0 +1,254 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { SingleCursorState, CursorColumns, CursorConfiguration, ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon'; +import { CursorChangeReason } from 'vs/editor/common/editorCommon'; +import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; + +export class CursorPosition { + _cursorPositionBrand: void; + + public readonly lineNumber: number; + public readonly column: number; + public readonly leftoverVisibleColumns: number; + + constructor(lineNumber: number, column: number, leftoverVisibleColumns: number) { + this.lineNumber = lineNumber; + this.column = column; + this.leftoverVisibleColumns = leftoverVisibleColumns; + } +} + +export class SingleMoveOperationResult { + _singleMoveOperationBrand: void; + + public static fromMove(initialState: SingleCursorState, inSelectionMode: boolean, lineNumber: number, column: number, leftoverVisibleColumns: number, ensureInEditableRange: boolean, reason: CursorChangeReason): SingleMoveOperationResult { + return new SingleMoveOperationResult( + initialState.move(inSelectionMode, new Position(lineNumber, column), leftoverVisibleColumns), + ensureInEditableRange, + reason + ); + } + + readonly state: SingleCursorState; + readonly ensureInEditableRange: boolean; + readonly reason: CursorChangeReason; + + constructor( + state: SingleCursorState, + ensureInEditableRange: boolean, + reason: CursorChangeReason + ) { + this.state = state; + this.ensureInEditableRange = ensureInEditableRange; + this.reason = reason; + } +} + +export class MoveOperations { + + public static left(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { + + if (column > model.getLineMinColumn(lineNumber)) { + if (CursorColumns.isLowSurrogate(model, lineNumber, column - 2)) { + // character before column is a low surrogate + column = column - 2; + } else { + column = column - 1; + } + } else if (lineNumber > 1) { + lineNumber = lineNumber - 1; + column = model.getLineMaxColumn(lineNumber); + } + + return new CursorPosition(lineNumber, column, 0); + } + + public static moveLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleMoveOperationResult { + let lineNumber: number, + column: number; + + if (cursor.hasSelection() && !inSelectionMode) { + // If we are in selection mode, move left without selection cancels selection and puts cursor at the beginning of the selection + lineNumber = cursor.selection.startLineNumber; + column = cursor.selection.startColumn; + } else { + let r = MoveOperations.left(config, model, cursor.position.lineNumber, cursor.position.column - (noOfColumns - 1)); + lineNumber = r.lineNumber; + column = r.column; + } + + return SingleMoveOperationResult.fromMove(cursor, inSelectionMode, lineNumber, column, 0, true, CursorChangeReason.Explicit); + } + + public static right(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number): CursorPosition { + + if (column < model.getLineMaxColumn(lineNumber)) { + if (CursorColumns.isHighSurrogate(model, lineNumber, column - 1)) { + // character after column is a high surrogate + column = column + 2; + } else { + column = column + 1; + } + } else if (lineNumber < model.getLineCount()) { + lineNumber = lineNumber + 1; + column = model.getLineMinColumn(lineNumber); + } + + return new CursorPosition(lineNumber, column, 0); + } + + public static moveRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleMoveOperationResult { + let lineNumber: number, + column: number; + + if (cursor.hasSelection() && !inSelectionMode) { + // If we are in selection mode, move right without selection cancels selection and puts cursor at the end of the selection + lineNumber = cursor.selection.endLineNumber; + column = cursor.selection.endColumn; + } else { + let r = MoveOperations.right(config, model, cursor.position.lineNumber, cursor.position.column + (noOfColumns - 1)); + lineNumber = r.lineNumber; + column = r.column; + } + + return SingleMoveOperationResult.fromMove(cursor, inSelectionMode, lineNumber, column, 0, true, CursorChangeReason.Explicit); + } + + public static down(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number, leftoverVisibleColumns: number, count: number, allowMoveOnLastLine: boolean): CursorPosition { + const currentVisibleColumn = CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize) + leftoverVisibleColumns; + + lineNumber = lineNumber + count; + var lineCount = model.getLineCount(); + if (lineNumber > lineCount) { + lineNumber = lineCount; + if (allowMoveOnLastLine) { + column = model.getLineMaxColumn(lineNumber); + } else { + column = Math.min(model.getLineMaxColumn(lineNumber), column); + if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { + column = column - 1; + } + } + } else { + column = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, currentVisibleColumn); + if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { + column = column - 1; + } + } + + leftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize); + + return new CursorPosition(lineNumber, column, leftoverVisibleColumns); + } + + public static moveDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, linesCount: number): SingleMoveOperationResult { + let lineNumber: number, + column: number; + + if (cursor.hasSelection() && !inSelectionMode) { + // If we are in selection mode, move down acts relative to the end of selection + lineNumber = cursor.selection.endLineNumber; + column = cursor.selection.endColumn; + } else { + lineNumber = cursor.position.lineNumber; + column = cursor.position.column; + } + + let r = MoveOperations.down(config, model, lineNumber, column, cursor.leftoverVisibleColumns, linesCount, true); + + return SingleMoveOperationResult.fromMove(cursor, inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns, true, CursorChangeReason.Explicit); + } + + public static translateDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): SingleMoveOperationResult { + let selection = cursor.selection; + + let selectionStart = MoveOperations.down(config, model, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.selectionStartLeftoverVisibleColumns, 1, false); + let position = MoveOperations.down(config, model, selection.positionLineNumber, selection.positionColumn, cursor.leftoverVisibleColumns, 1, false); + + let tmp = new SingleCursorState( + new Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column), + selectionStart.leftoverVisibleColumns, + new Position(position.lineNumber, position.column), + position.leftoverVisibleColumns + ); + + return new SingleMoveOperationResult(tmp, true, CursorChangeReason.Explicit); + } + + public static up(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number, leftoverVisibleColumns: number, count: number, allowMoveOnFirstLine: boolean): CursorPosition { + const currentVisibleColumn = CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize) + leftoverVisibleColumns; + + lineNumber = lineNumber - count; + if (lineNumber < 1) { + lineNumber = 1; + if (allowMoveOnFirstLine) { + column = model.getLineMinColumn(lineNumber); + } else { + column = Math.min(model.getLineMaxColumn(lineNumber), column); + if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { + column = column - 1; + } + } + } else { + column = CursorColumns.columnFromVisibleColumn2(config, model, lineNumber, currentVisibleColumn); + if (CursorColumns.isInsideSurrogatePair(model, lineNumber, column)) { + column = column - 1; + } + } + + leftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize); + + return new CursorPosition(lineNumber, column, leftoverVisibleColumns); + } + + public static moveUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, linesCount: number): SingleMoveOperationResult { + let lineNumber: number, + column: number; + + if (cursor.hasSelection() && !inSelectionMode) { + // If we are in selection mode, move up acts relative to the beginning of selection + lineNumber = cursor.selection.startLineNumber; + column = cursor.selection.startColumn; + } else { + lineNumber = cursor.position.lineNumber; + column = cursor.position.column; + } + + let r = MoveOperations.up(config, model, lineNumber, column, cursor.leftoverVisibleColumns, linesCount, true); + + return SingleMoveOperationResult.fromMove(cursor, inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns, true, CursorChangeReason.Explicit); + } + + public static translateUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): SingleMoveOperationResult { + + let selection = cursor.selection; + + let selectionStart = MoveOperations.up(config, model, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.selectionStartLeftoverVisibleColumns, 1, false); + let position = MoveOperations.up(config, model, selection.positionLineNumber, selection.positionColumn, cursor.leftoverVisibleColumns, 1, false); + + let tmp = new SingleCursorState( + new Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column), + selectionStart.leftoverVisibleColumns, + new Position(position.lineNumber, position.column), + position.leftoverVisibleColumns + ); + + return new SingleMoveOperationResult(tmp, true, CursorChangeReason.Explicit); + } + + public static moveToBeginningOfBuffer(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleMoveOperationResult { + return SingleMoveOperationResult.fromMove(cursor, inSelectionMode, 1, 1, 0, true, CursorChangeReason.Explicit); + } + + public static moveToEndOfBuffer(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleMoveOperationResult { + let lastLineNumber = model.getLineCount(); + let lastColumn = model.getLineMaxColumn(lastLineNumber); + + return SingleMoveOperationResult.fromMove(cursor, inSelectionMode, lastLineNumber, lastColumn, 0, true, CursorChangeReason.Explicit); + } +} diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts new file mode 100644 index 00000000000..0aea7fc6b70 --- /dev/null +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -0,0 +1,468 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { onUnexpectedError } from 'vs/base/common/errors'; +import { ReplaceCommand, ReplaceCommandWithoutChangingPosition, ReplaceCommandWithOffsetCursorState } from 'vs/editor/common/commands/replaceCommand'; +import { SingleCursorState, EditOperationResult, CursorColumns, CursorConfiguration, ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon'; +import { Range } from 'vs/editor/common/core/range'; +import { CursorChangeReason, ICommand } from 'vs/editor/common/editorCommon'; +import * as strings from 'vs/base/common/strings'; +import { ShiftCommand } from 'vs/editor/common/commands/shiftCommand'; +import { Selection } from 'vs/editor/common/core/selection'; +import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; +import { ITokenizedModel } from 'vs/editor/common/editorCommon'; +import { IndentAction } from 'vs/editor/common/modes/languageConfiguration'; +import { CharCode } from 'vs/base/common/charCode'; +import { SurroundSelectionCommand } from 'vs/editor/common/commands/surroundSelectionCommand'; +import { IElectricAction } from 'vs/editor/common/modes/supports/electricCharacter'; + +export class TypeOperations { + + public static indent(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + return new EditOperationResult( + new ShiftCommand(cursor.selection, { + isUnshift: false, + tabSize: config.tabSize, + oneIndent: config.oneIndent + }), { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: true, + shouldRevealHorizontal: false + } + ); + } + + public static outdent(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + return new EditOperationResult( + new ShiftCommand(cursor.selection, { + isUnshift: true, + tabSize: config.tabSize, + oneIndent: config.oneIndent + }), { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: true, + shouldRevealHorizontal: false + } + ); + } + + public static paste(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, text: string, pasteOnNewLine: boolean): EditOperationResult { + let position = cursor.position; + let selection = cursor.selection; + + if (pasteOnNewLine && text.indexOf('\n') !== text.length - 1) { + pasteOnNewLine = false; + } + if (pasteOnNewLine && selection.startLineNumber !== selection.endLineNumber) { + pasteOnNewLine = false; + } + if (pasteOnNewLine && selection.startColumn === model.getLineMinColumn(selection.startLineNumber) && selection.endColumn === model.getLineMaxColumn(selection.startLineNumber)) { + pasteOnNewLine = false; + } + + if (pasteOnNewLine) { + // Paste entire line at the beginning of line + + let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, 1); + return new EditOperationResult(new ReplaceCommand(typeSelection, text), { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: true, + cursorPositionChangeReason: CursorChangeReason.Paste + }); + } + + return new EditOperationResult(new ReplaceCommand(selection, text), { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: true, + cursorPositionChangeReason: CursorChangeReason.Paste + }); + } + + private static _goodIndentForLine(config: CursorConfiguration, model: ITokenizedModel, lineNumber: number): string { + let lastLineNumber = lineNumber - 1; + + for (lastLineNumber = lineNumber - 1; lastLineNumber >= 1; lastLineNumber--) { + let lineText = model.getLineContent(lastLineNumber); + let nonWhitespaceIdx = strings.lastNonWhitespaceIndex(lineText); + if (nonWhitespaceIdx >= 0) { + break; + } + } + + if (lastLineNumber < 1) { + // No previous line with content found + return '\t'; + } + + let r = LanguageConfigurationRegistry.getEnterActionAtPosition(model, lastLineNumber, model.getLineMaxColumn(lastLineNumber)); + + let indentation: string; + if (r.enterAction.indentAction === IndentAction.Outdent) { + let desiredIndentCount = ShiftCommand.unshiftIndentCount(r.indentation, r.indentation.length, config.tabSize); + indentation = ''; + for (let i = 0; i < desiredIndentCount; i++) { + indentation += '\t'; + } + indentation = config.normalizeIndentation(indentation); + } else { + indentation = r.indentation; + } + + let result = indentation + r.enterAction.appendText; + if (result.length === 0) { + // good position is at column 1, but we gotta do something... + return '\t'; + } + return result; + } + + private static _replaceJumpToNextIndent(config: CursorConfiguration, model: ICursorSimpleModel, selection: Selection): ReplaceCommand { + let typeText = ''; + + let position = selection.getStartPosition(); + if (config.insertSpaces) { + let visibleColumnFromColumn = CursorColumns.visibleColumnFromColumn2(config, model, position); + let tabSize = config.tabSize; + let spacesCnt = tabSize - (visibleColumnFromColumn % tabSize); + for (let i = 0; i < spacesCnt; i++) { + typeText += ' '; + } + } else { + typeText = '\t'; + } + + return new ReplaceCommand(selection, typeText); + } + + public static tab(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState): EditOperationResult { + let selection = cursor.selection; + + if (selection.isEmpty()) { + + let lineText = model.getLineContent(selection.startLineNumber); + + if (/^\s*$/.test(lineText)) { + let possibleTypeText = config.normalizeIndentation(this._goodIndentForLine(config, model, selection.startLineNumber)); + if (!strings.startsWith(lineText, possibleTypeText)) { + let command = new ReplaceCommand(new Range(selection.startLineNumber, 1, selection.startLineNumber, lineText.length + 1), possibleTypeText); + return new EditOperationResult(command, { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false, + isAutoWhitespaceCommand: true + }); + } + } + + return new EditOperationResult(this._replaceJumpToNextIndent(config, model, selection), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false, + isAutoWhitespaceCommand: true + }); + } else { + if (selection.startLineNumber === selection.endLineNumber) { + let lineMaxColumn = model.getLineMaxColumn(selection.startLineNumber); + if (selection.startColumn !== 1 || selection.endColumn !== lineMaxColumn) { + // This is a single line selection that is not the entire line + return new EditOperationResult(this._replaceJumpToNextIndent(config, model, selection), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + } + + return this.indent(config, model, cursor); + } + } + + public static replacePreviousChar(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState, txt: string, replaceCharCnt: number): EditOperationResult { + let pos = cursor.position; + let startColumn = Math.max(1, pos.column - replaceCharCnt); + let range = new Range(pos.lineNumber, startColumn, pos.lineNumber, pos.column); + return new EditOperationResult(new ReplaceCommand(range, txt), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + + public static typeCommand(range: Range, text: string, keepPosition: boolean): ICommand { + if (keepPosition) { + return new ReplaceCommandWithoutChangingPosition(range, text); + } else { + return new ReplaceCommand(range, text); + } + } + + private static _enter(config: CursorConfiguration, model: ITokenizedModel, keepPosition: boolean, range: Range): EditOperationResult { + + let r = LanguageConfigurationRegistry.getEnterActionAtPosition(model, range.startLineNumber, range.startColumn); + let enterAction = r.enterAction; + let indentation = r.indentation; + + let executeCommand: ICommand; + if (enterAction.indentAction === IndentAction.None) { + // Nothing special + executeCommand = TypeOperations.typeCommand(range, '\n' + config.normalizeIndentation(indentation + enterAction.appendText), keepPosition); + + } else if (enterAction.indentAction === IndentAction.Indent) { + // Indent once + executeCommand = TypeOperations.typeCommand(range, '\n' + config.normalizeIndentation(indentation + enterAction.appendText), keepPosition); + + } else if (enterAction.indentAction === IndentAction.IndentOutdent) { + // Ultra special + let normalIndent = config.normalizeIndentation(indentation); + let increasedIndent = config.normalizeIndentation(indentation + enterAction.appendText); + + let typeText = '\n' + increasedIndent + '\n' + normalIndent; + + if (keepPosition) { + executeCommand = new ReplaceCommandWithoutChangingPosition(range, typeText); + } else { + executeCommand = new ReplaceCommandWithOffsetCursorState(range, typeText, -1, increasedIndent.length - normalIndent.length); + } + } else if (enterAction.indentAction === IndentAction.Outdent) { + let desiredIndentCount = ShiftCommand.unshiftIndentCount(indentation, indentation.length + 1, config.tabSize); + let actualIndentation = ''; + for (let i = 0; i < desiredIndentCount; i++) { + actualIndentation += '\t'; + } + executeCommand = TypeOperations.typeCommand(range, '\n' + config.normalizeIndentation(actualIndentation + enterAction.appendText), keepPosition); + } + + return new EditOperationResult(executeCommand, { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: false, + isAutoWhitespaceCommand: true + }); + } + + private static _typeInterceptorEnter(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState, ch: string): EditOperationResult { + if (ch !== '\n') { + return null; + } + + return TypeOperations._enter(config, model, false, cursor.selection); + } + + private static _typeInterceptorAutoClosingCloseChar(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState, ch: string): EditOperationResult { + if (!config.autoClosingBrackets) { + return null; + } + + let selection = cursor.selection; + + if (!selection.isEmpty() || !config.autoClosingPairsClose.hasOwnProperty(ch)) { + return null; + } + + let position = cursor.position; + + let lineText = model.getLineContent(position.lineNumber); + let beforeCharacter = lineText.charAt(position.column - 1); + + if (beforeCharacter !== ch) { + return null; + } + + let typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1); + return new EditOperationResult(new ReplaceCommand(typeSelection, ch), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + + private static _typeInterceptorAutoClosingOpenChar(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState, ch: string): EditOperationResult { + if (!config.autoClosingBrackets) { + return null; + } + + let selection = cursor.selection; + + if (!selection.isEmpty() || !config.autoClosingPairsOpen.hasOwnProperty(ch)) { + return null; + } + + let position = cursor.position; + let lineText = model.getLineContent(position.lineNumber); + let beforeCharacter = lineText.charAt(position.column - 1); + + // Only consider auto closing the pair if a space follows or if another autoclosed pair follows + if (beforeCharacter) { + let isBeforeCloseBrace = false; + for (let closeBrace in config.autoClosingPairsClose) { + if (beforeCharacter === closeBrace) { + isBeforeCloseBrace = true; + break; + } + } + if (!isBeforeCloseBrace && !/\s/.test(beforeCharacter)) { + return null; + } + } + + let lineTokens = model.getLineTokens(position.lineNumber, false); + + let shouldAutoClosePair = false; + try { + shouldAutoClosePair = LanguageConfigurationRegistry.shouldAutoClosePair(ch, lineTokens, position.column); + } catch (e) { + onUnexpectedError(e); + } + + if (!shouldAutoClosePair) { + return null; + } + + let closeCharacter = config.autoClosingPairsOpen[ch]; + return new EditOperationResult(new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length), { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: false + }); + } + + private static _typeInterceptorSurroundSelection(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState, ch: string): EditOperationResult { + if (!config.autoClosingBrackets) { + return null; + } + + let selection = cursor.selection; + + if (selection.isEmpty() || !config.surroundingPairs.hasOwnProperty(ch)) { + return null; + } + + let selectionContainsOnlyWhitespace = true; + + for (let lineNumber = selection.startLineNumber; lineNumber <= selection.endLineNumber; lineNumber++) { + let lineText = model.getLineContent(lineNumber); + let startIndex = (lineNumber === selection.startLineNumber ? selection.startColumn - 1 : 0); + let endIndex = (lineNumber === selection.endLineNumber ? selection.endColumn - 1 : lineText.length); + for (let charIndex = startIndex; charIndex < endIndex; charIndex++) { + let charCode = lineText.charCodeAt(charIndex); + if (charCode !== CharCode.Tab && charCode !== CharCode.Space) { + selectionContainsOnlyWhitespace = false; + + // Break outer loop + lineNumber = selection.endLineNumber + 1; + + // Break inner loop + charIndex = endIndex; + } + } + } + + if (selectionContainsOnlyWhitespace) { + return null; + } + + let closeCharacter = config.surroundingPairs[ch]; + + return new EditOperationResult(new SurroundSelectionCommand(selection, ch, closeCharacter), { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: true + }); + } + + private static _typeInterceptorElectricChar(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState, ch: string): EditOperationResult { + if (!config.electricChars.hasOwnProperty(ch)) { + return null; + } + + let position = cursor.position; + let lineTokens = model.getLineTokens(position.lineNumber, false); + + let electricAction: IElectricAction; + try { + electricAction = LanguageConfigurationRegistry.onElectricCharacter(ch, lineTokens, position.column); + } catch (e) { + onUnexpectedError(e); + } + + if (!electricAction) { + return null; + } + + if (electricAction.appendText) { + return new EditOperationResult(new ReplaceCommandWithOffsetCursorState(cursor.selection, ch + electricAction.appendText, 0, -electricAction.appendText.length), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: true + }); + } + + if (electricAction.matchOpenBracket) { + let match = model.findMatchingBracketUp(electricAction.matchOpenBracket, { + lineNumber: position.lineNumber, + column: position.column + }); + + if (match) { + let matchLine = model.getLineContent(match.startLineNumber); + let matchLineIndentation = strings.getLeadingWhitespace(matchLine); + let newIndentation = config.normalizeIndentation(matchLineIndentation); + + let lineText = model.getLineContent(position.lineNumber); + let lineFirstNonBlankColumn = model.getLineFirstNonWhitespaceColumn(position.lineNumber) || position.column; + + let prefix = lineText.substring(lineFirstNonBlankColumn - 1, position.column - 1); + let typeText = newIndentation + prefix + ch; + + let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column); + + return new EditOperationResult(new ReplaceCommand(typeSelection, typeText), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: true + }); + } + } + + return null; + } + + public static typeWithInterceptors(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState, ch: string): EditOperationResult { + let r: EditOperationResult = null; + + r = r || this._typeInterceptorEnter(config, model, cursor, ch); + r = r || this._typeInterceptorAutoClosingCloseChar(config, model, cursor, ch); + r = r || this._typeInterceptorAutoClosingOpenChar(config, model, cursor, ch); + r = r || this._typeInterceptorSurroundSelection(config, model, cursor, ch); + r = r || this._typeInterceptorElectricChar(config, model, cursor, ch); + r = r || this.typeWithoutInterceptors(config, model, cursor, ch); + + return r; + } + + public static typeWithoutInterceptors(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState, str: string): EditOperationResult { + return new EditOperationResult(TypeOperations.typeCommand(cursor.selection, str, false), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + + public static lineInsertBefore(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState): EditOperationResult { + let lineNumber = cursor.position.lineNumber; + + if (lineNumber === 1) { + return new EditOperationResult(new ReplaceCommandWithoutChangingPosition(new Range(1, 1, 1, 1), '\n'), { + shouldPushStackElementBefore: true, + shouldPushStackElementAfter: true + }); + } + + lineNumber--; + let column = model.getLineMaxColumn(lineNumber); + + return this._enter(config, model, false, new Range(lineNumber, column, lineNumber, column)); + } + + public static lineInsertAfter(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState): EditOperationResult { + let position = cursor.position; + let column = model.getLineMaxColumn(position.lineNumber); + return this._enter(config, model, false, new Range(position.lineNumber, column, position.lineNumber, column)); + } + + public static lineBreakInsert(config: CursorConfiguration, model: ITokenizedModel, cursor: SingleCursorState): EditOperationResult { + return this._enter(config, model, true, cursor.selection); + } +} diff --git a/src/vs/editor/common/controller/cursorWordOperations.ts b/src/vs/editor/common/controller/cursorWordOperations.ts new file mode 100644 index 00000000000..1fe6a5fe5f1 --- /dev/null +++ b/src/vs/editor/common/controller/cursorWordOperations.ts @@ -0,0 +1,513 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { SingleCursorState, EditOperationResult, CursorConfiguration, ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon'; +import { Position } from 'vs/editor/common/core/position'; +import { CharCode } from 'vs/base/common/charCode'; +import { CharacterClassifier } from 'vs/editor/common/core/characterClassifier'; +import { SingleMoveOperationResult } from 'vs/editor/common/controller/cursorMoveOperations'; +import { CursorChangeReason } from 'vs/editor/common/editorCommon'; +import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; +import * as strings from 'vs/base/common/strings'; +import { Range } from 'vs/editor/common/core/range'; +import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; + +export interface IFindWordResult { + /** + * The index where the word starts. + */ + start: number; + /** + * The index where the word ends. + */ + end: number; + /** + * The word type. + */ + wordType: WordType; +} + +export const enum WordType { + None = 0, + Regular = 1, + Separator = 2 +} + +const enum CharacterClass { + Regular = 0, + Whitespace = 1, + WordSeparator = 2 +} + +export const enum WordNavigationType { + WordStart = 0, + WordEnd = 1 +} + +class WordCharacterClassifier extends CharacterClassifier { + + constructor(wordSeparators: string) { + super(CharacterClass.Regular); + + for (let i = 0, len = wordSeparators.length; i < len; i++) { + this.set(wordSeparators.charCodeAt(i), CharacterClass.WordSeparator); + } + + this.set(CharCode.Space, CharacterClass.Whitespace); + this.set(CharCode.Tab, CharacterClass.Whitespace); + } + +} + +function once(computeFn: (input: string) => R): (input: string) => R { + let cache: { [key: string]: R; } = {}; // TODO@Alex unbounded cache + return (input: string): R => { + if (!cache.hasOwnProperty(input)) { + cache[input] = computeFn(input); + } + return cache[input]; + }; +} + +let getMapForWordSeparators = once( + (input) => new WordCharacterClassifier(input) +); + +export class WordOperations { + + private static _createWord(lineContent: string, wordType: WordType, start: number, end: number): IFindWordResult { + // console.log('WORD ==> ' + start + ' => ' + end + ':::: <<<' + lineContent.substring(start, end) + '>>>'); + return { start: start, end: end, wordType: wordType }; + } + + public static findPreviousWordOnLine(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): IFindWordResult { + let wordSeparators = getMapForWordSeparators(config.wordSeparators); + let lineContent = model.getLineContent(position.lineNumber); + return this._findPreviousWordOnLine(lineContent, wordSeparators, position); + } + + private static _findPreviousWordOnLine(lineContent: string, wordSeparators: WordCharacterClassifier, position: Position): IFindWordResult { + let wordType = WordType.None; + for (let chIndex = position.column - 2; chIndex >= 0; chIndex--) { + let chCode = lineContent.charCodeAt(chIndex); + let chClass = wordSeparators.get(chCode); + + if (chClass === CharacterClass.Regular) { + if (wordType === WordType.Separator) { + return this._createWord(lineContent, wordType, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); + } + wordType = WordType.Regular; + } else if (chClass === CharacterClass.WordSeparator) { + if (wordType === WordType.Regular) { + return this._createWord(lineContent, wordType, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); + } + wordType = WordType.Separator; + } else if (chClass === CharacterClass.Whitespace) { + if (wordType !== WordType.None) { + return this._createWord(lineContent, wordType, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); + } + } + } + + if (wordType !== WordType.None) { + return this._createWord(lineContent, wordType, 0, this._findEndOfWord(lineContent, wordSeparators, wordType, 0)); + } + + return null; + } + + private static _findEndOfWord(lineContent: string, wordSeparators: WordCharacterClassifier, wordType: WordType, startIndex: number): number { + let len = lineContent.length; + for (let chIndex = startIndex; chIndex < len; chIndex++) { + let chCode = lineContent.charCodeAt(chIndex); + let chClass = wordSeparators.get(chCode); + + if (chClass === CharacterClass.Whitespace) { + return chIndex; + } + if (wordType === WordType.Regular && chClass === CharacterClass.WordSeparator) { + return chIndex; + } + if (wordType === WordType.Separator && chClass === CharacterClass.Regular) { + return chIndex; + } + } + return len; + } + + public static findNextWordOnLine(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): IFindWordResult { + let wordSeparators = getMapForWordSeparators(config.wordSeparators); + let lineContent = model.getLineContent(position.lineNumber); + return this._findNextWordOnLine(lineContent, wordSeparators, position); + } + + private static _findNextWordOnLine(lineContent: string, wordSeparators: WordCharacterClassifier, position: Position): IFindWordResult { + let wordType = WordType.None; + let len = lineContent.length; + + for (let chIndex = position.column - 1; chIndex < len; chIndex++) { + let chCode = lineContent.charCodeAt(chIndex); + let chClass = wordSeparators.get(chCode); + + if (chClass === CharacterClass.Regular) { + if (wordType === WordType.Separator) { + return this._createWord(lineContent, wordType, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); + } + wordType = WordType.Regular; + } else if (chClass === CharacterClass.WordSeparator) { + if (wordType === WordType.Regular) { + return this._createWord(lineContent, wordType, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); + } + wordType = WordType.Separator; + } else if (chClass === CharacterClass.Whitespace) { + if (wordType !== WordType.None) { + return this._createWord(lineContent, wordType, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); + } + } + } + + if (wordType !== WordType.None) { + return this._createWord(lineContent, wordType, this._findStartOfWord(lineContent, wordSeparators, wordType, len - 1), len); + } + + return null; + } + + private static _findStartOfWord(lineContent: string, wordSeparators: WordCharacterClassifier, wordType: WordType, startIndex: number): number { + for (let chIndex = startIndex; chIndex >= 0; chIndex--) { + let chCode = lineContent.charCodeAt(chIndex); + let chClass = wordSeparators.get(chCode); + + if (chClass === CharacterClass.Whitespace) { + return chIndex + 1; + } + if (wordType === WordType.Regular && chClass === CharacterClass.WordSeparator) { + return chIndex + 1; + } + if (wordType === WordType.Separator && chClass === CharacterClass.Regular) { + return chIndex + 1; + } + } + return 0; + } + + public static moveWordLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, wordNavigationType: WordNavigationType): SingleMoveOperationResult { + let position = cursor.position; + let lineNumber = position.lineNumber; + let column = position.column; + + if (column === 1) { + if (lineNumber > 1) { + lineNumber = lineNumber - 1; + column = model.getLineMaxColumn(lineNumber); + } + } + + let prevWordOnLine = WordOperations.findPreviousWordOnLine(config, model, new Position(lineNumber, column)); + + if (wordNavigationType === WordNavigationType.WordStart) { + if (prevWordOnLine) { + column = prevWordOnLine.start + 1; + } else { + column = 1; + } + } else { + if (prevWordOnLine && column <= prevWordOnLine.end + 1) { + prevWordOnLine = WordOperations.findPreviousWordOnLine(config, model, new Position(lineNumber, prevWordOnLine.start + 1)); + } + if (prevWordOnLine) { + column = prevWordOnLine.end + 1; + } else { + column = 1; + } + } + + return SingleMoveOperationResult.fromMove(cursor, inSelectionMode, lineNumber, column, 0, true, CursorChangeReason.Explicit); + } + + public static moveWordRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, wordNavigationType: WordNavigationType): SingleMoveOperationResult { + let position = cursor.position; + let lineNumber = position.lineNumber; + let column = position.column; + + if (column === model.getLineMaxColumn(lineNumber)) { + if (lineNumber < model.getLineCount()) { + lineNumber = lineNumber + 1; + column = 1; + } + } + + let nextWordOnLine = WordOperations.findNextWordOnLine(config, model, new Position(lineNumber, column)); + + if (wordNavigationType === WordNavigationType.WordEnd) { + if (nextWordOnLine) { + column = nextWordOnLine.end + 1; + } else { + column = model.getLineMaxColumn(lineNumber); + } + } else { + if (nextWordOnLine && column >= nextWordOnLine.start + 1) { + nextWordOnLine = WordOperations.findNextWordOnLine(config, model, new Position(lineNumber, nextWordOnLine.end + 1)); + } + if (nextWordOnLine) { + column = nextWordOnLine.start + 1; + } else { + column = model.getLineMaxColumn(lineNumber); + } + } + + return SingleMoveOperationResult.fromMove(cursor, inSelectionMode, lineNumber, column, 0, true, CursorChangeReason.Explicit); + } + + private static _deleteWordLeftWhitespace(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + let position = cursor.position; + let lineContent = model.getLineContent(position.lineNumber); + let startIndex = position.column - 2; + let lastNonWhitespace = strings.lastNonWhitespaceIndex(lineContent, startIndex); + if (lastNonWhitespace + 1 < startIndex) { + let deleteRange = new Range(position.lineNumber, lastNonWhitespace + 2, position.lineNumber, position.column); + return new EditOperationResult(new ReplaceCommand(deleteRange, ''), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + return null; + } + + public static deleteWordLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType): EditOperationResult { + let r = DeleteOperations.autoClosingPairDelete(config, model, cursor); + if (r) { + // This was a case for an auto-closing pair delete + return r; + } + + let selection = cursor.selection; + + if (selection.isEmpty()) { + let position = cursor.position; + + let lineNumber = position.lineNumber; + let column = position.column; + + if (lineNumber === 1 && column === 1) { + // Ignore deleting at beginning of file + return null; + } + + if (whitespaceHeuristics) { + let r = this._deleteWordLeftWhitespace(config, model, cursor); + if (r) { + return r; + } + } + + let prevWordOnLine = WordOperations.findPreviousWordOnLine(config, model, position); + + if (wordNavigationType === WordNavigationType.WordStart) { + if (prevWordOnLine) { + column = prevWordOnLine.start + 1; + } else { + column = 1; + } + } else { + if (prevWordOnLine && column <= prevWordOnLine.end + 1) { + prevWordOnLine = WordOperations.findPreviousWordOnLine(config, model, new Position(lineNumber, prevWordOnLine.start + 1)); + } + if (prevWordOnLine) { + column = prevWordOnLine.end + 1; + } else { + column = 1; + } + } + + let deleteSelection = new Range(lineNumber, column, lineNumber, position.column); + if (!deleteSelection.isEmpty()) { + return new EditOperationResult(new ReplaceCommand(deleteSelection, ''), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + } + + return DeleteOperations.deleteLeft(config, model, cursor); + } + + private static _findFirstNonWhitespaceChar(str: string, startIndex: number): number { + let len = str.length; + for (let chIndex = startIndex; chIndex < len; chIndex++) { + let ch = str.charAt(chIndex); + if (ch !== ' ' && ch !== '\t') { + return chIndex; + } + } + return len; + } + + private static _deleteWordRightWhitespace(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): EditOperationResult { + let position = cursor.position; + let lineContent = model.getLineContent(position.lineNumber); + let startIndex = position.column - 1; + let firstNonWhitespace = this._findFirstNonWhitespaceChar(lineContent, startIndex); + if (startIndex + 1 < firstNonWhitespace) { + // bingo + let deleteRange = new Range(position.lineNumber, position.column, position.lineNumber, firstNonWhitespace + 1); + return new EditOperationResult(new ReplaceCommand(deleteRange, ''), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + return null; + } + + public static deleteWordRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType): EditOperationResult { + + let selection = cursor.selection; + + if (selection.isEmpty()) { + let position = cursor.position; + + let lineNumber = position.lineNumber; + let column = position.column; + + let lineCount = model.getLineCount(); + let maxColumn = model.getLineMaxColumn(lineNumber); + if (lineNumber === lineCount && column === maxColumn) { + // Ignore deleting at end of file + return null; + } + + if (whitespaceHeuristics) { + let r = this._deleteWordRightWhitespace(config, model, cursor); + if (r) { + return r; + } + } + + let nextWordOnLine = WordOperations.findNextWordOnLine(config, model, position); + + if (wordNavigationType === WordNavigationType.WordEnd) { + if (nextWordOnLine) { + column = nextWordOnLine.end + 1; + } else { + if (column < maxColumn || lineNumber === lineCount) { + column = maxColumn; + } else { + lineNumber++; + nextWordOnLine = WordOperations.findNextWordOnLine(config, model, new Position(lineNumber, 1)); + if (nextWordOnLine) { + column = nextWordOnLine.start + 1; + } else { + column = model.getLineMaxColumn(lineNumber); + } + } + } + } else { + if (nextWordOnLine && column >= nextWordOnLine.start + 1) { + nextWordOnLine = WordOperations.findNextWordOnLine(config, model, new Position(lineNumber, nextWordOnLine.end + 1)); + } + if (nextWordOnLine) { + column = nextWordOnLine.start + 1; + } else { + if (column < maxColumn || lineNumber === lineCount) { + column = maxColumn; + } else { + lineNumber++; + nextWordOnLine = WordOperations.findNextWordOnLine(config, model, new Position(lineNumber, 1)); + if (nextWordOnLine) { + column = nextWordOnLine.start + 1; + } else { + column = model.getLineMaxColumn(lineNumber); + } + } + } + } + + let deleteSelection = new Range(lineNumber, column, position.lineNumber, position.column); + if (!deleteSelection.isEmpty()) { + return new EditOperationResult(new ReplaceCommand(deleteSelection, ''), { + shouldPushStackElementBefore: false, + shouldPushStackElementAfter: false + }); + } + } + + // fall back to normal deleteRight behavior + return DeleteOperations.deleteRight(config, model, cursor); + } + + public static word(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, position: Position): SingleMoveOperationResult { + let prevWord = WordOperations.findPreviousWordOnLine(config, model, position); + let isInPrevWord = (prevWord && prevWord.wordType === WordType.Regular && prevWord.start < position.column - 1 && position.column - 1 <= prevWord.end); + let nextWord = WordOperations.findNextWordOnLine(config, model, position); + let isInNextWord = (nextWord && nextWord.wordType === WordType.Regular && nextWord.start < position.column - 1 && position.column - 1 <= nextWord.end); + + if (!inSelectionMode || !cursor.hasSelection()) { + + let startColumn: number; + let endColumn: number; + + if (isInPrevWord) { + startColumn = prevWord.start + 1; + endColumn = prevWord.end + 1; + } else if (isInNextWord) { + startColumn = nextWord.start + 1; + endColumn = nextWord.end + 1; + } else { + if (prevWord) { + startColumn = prevWord.end + 1; + } else { + startColumn = 1; + } + if (nextWord) { + endColumn = nextWord.start + 1; + } else { + endColumn = model.getLineMaxColumn(position.lineNumber); + } + } + + return new SingleMoveOperationResult( + new SingleCursorState( + new Range(position.lineNumber, startColumn, position.lineNumber, endColumn), 0, + new Position(position.lineNumber, endColumn), 0 + ), + false, + CursorChangeReason.Explicit + ); + } + + let startColumn: number; + let endColumn: number; + + if (isInPrevWord) { + startColumn = prevWord.start + 1; + endColumn = prevWord.end + 1; + } else if (isInNextWord) { + startColumn = nextWord.start + 1; + endColumn = nextWord.end + 1; + } else { + startColumn = position.column; + endColumn = position.column; + } + + let lineNumber = position.lineNumber; + let column: number; + if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) { + column = startColumn; + let possiblePosition = new Position(lineNumber, column); + if (cursor.selectionStart.containsPosition(possiblePosition)) { + column = cursor.selectionStart.endColumn; + } + } else { + column = endColumn; + let possiblePosition = new Position(lineNumber, column); + if (cursor.selectionStart.containsPosition(possiblePosition)) { + column = cursor.selectionStart.startColumn; + } + } + + return SingleMoveOperationResult.fromMove(cursor, cursor.hasSelection(), lineNumber, column, 0, false, CursorChangeReason.Explicit); + } +} diff --git a/src/vs/editor/common/controller/oneCursor.ts b/src/vs/editor/common/controller/oneCursor.ts index d2ad9252588..e0ee4e876fb 100644 --- a/src/vs/editor/common/controller/oneCursor.ts +++ b/src/vs/editor/common/controller/oneCursor.ts @@ -4,26 +4,16 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { onUnexpectedError, illegalArgument } from 'vs/base/common/errors'; -import * as strings from 'vs/base/common/strings'; -import { ReplaceCommand, ReplaceCommandWithOffsetCursorState, ReplaceCommandWithoutChangingPosition } from 'vs/editor/common/commands/replaceCommand'; -import { ShiftCommand } from 'vs/editor/common/commands/shiftCommand'; -import { SurroundSelectionCommand } from 'vs/editor/common/commands/surroundSelectionCommand'; -import { CursorMoveHelper, CursorMove, CursorMoveConfiguration, ICursorMoveHelperModel, IColumnSelectResult, IViewColumnSelectResult } from 'vs/editor/common/controller/cursorMoveHelper'; +import { illegalArgument } from 'vs/base/common/errors'; +import { CursorMoveHelper } from 'vs/editor/common/controller/cursorMoveHelper'; +import { SingleCursorState, CursorConfiguration, ICursorSimpleModel } from 'vs/editor/common/controller/cursorCommon'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { Selection, SelectionDirection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { IndentAction } from 'vs/editor/common/modes/languageConfiguration'; -import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; -import { CharCode } from 'vs/base/common/charCode'; -import { CharacterClassifier } from 'vs/editor/common/core/characterClassifier'; -import { IElectricAction } from 'vs/editor/common/modes/supports/electricCharacter'; import { IDisposable } from 'vs/base/common/lifecycle'; - -export interface IPostOperationRunnable { - (ctx: IOneCursorOperationContext): void; -} +import { MoveOperations, SingleMoveOperationResult } from 'vs/editor/common/controller/cursorMoveOperations'; +import { WordOperations, WordNavigationType } from 'vs/editor/common/controller/cursorWordOperations'; export interface IOneCursorOperationContext { cursorPositionChangeReason: editorCommon.CursorChangeReason; @@ -34,7 +24,6 @@ export interface IOneCursorOperationContext { shouldPushStackElementAfter: boolean; executeCommand: editorCommon.ICommand; isAutoWhitespaceCommand: boolean; - postOperationRunnable: IPostOperationRunnable; } export interface IModeConfiguration { @@ -63,7 +52,7 @@ export interface CursorMoveArguments extends editorCommon.CursorMoveArguments { export interface IViewModelHelper { - viewModel: ICursorMoveHelperModel; + viewModel: ICursorSimpleModel; getCurrentCompletelyVisibleViewLinesRangeInViewport(): Range; getCurrentCompletelyVisibleModelLinesRangeInViewport(): Range; @@ -73,10 +62,9 @@ export interface IViewModelHelper { convertViewToModelPosition(lineNumber: number, column: number): Position; convertViewSelectionToModelSelection(viewSelection: Selection): Selection; - convertViewRangeToModelRange(viewRange: Range): Range; - validateViewPosition(viewLineNumber: number, viewColumn: number, modelPosition: Position): Position; - validateViewRange(viewStartLineNumber: number, viewStartColumn: number, viewEndLineNumber: number, viewEndColumn: number, modelRange: Range): Range; + validateViewPosition(viewPosition: Position, modelPosition: Position): Position; + validateViewRange(viewRange: Range, modelRange: Range): Range; } export interface IOneCursorState { @@ -88,144 +76,33 @@ export interface IOneCursorState { selectionStartLeftoverVisibleColumns: number; } -export interface IFindWordResult { - /** - * The index where the word starts. - */ - start: number; - /** - * The index where the word ends. - */ - end: number; - /** - * The word type. - */ - wordType: WordType; -} -export const enum WordType { - None = 0, - Regular = 1, - Separator = 2 -}; - -const enum CharacterClass { - Regular = 0, - Whitespace = 1, - WordSeparator = 2 -}; - -export const enum WordNavigationType { - WordStart = 0, - WordEnd = 1 -} - -/** - * Represents the cursor state on either the model or on the view model. - */ -export class CursorModelState { - _cursorModelStateBrand: void; - - // --- selection can start as a range (think double click and drag) - public readonly selectionStart: Range; - public readonly selectionStartLeftoverVisibleColumns: number; - public readonly position: Position; - public readonly leftoverVisibleColumns: number; - public readonly selection: Selection; - - constructor( - selectionStart: Range, - selectionStartLeftoverVisibleColumns: number, - position: Position, - leftoverVisibleColumns: number, - ) { - this.selectionStart = selectionStart; - this.selectionStartLeftoverVisibleColumns = selectionStartLeftoverVisibleColumns; - this.position = position; - this.leftoverVisibleColumns = leftoverVisibleColumns; - this.selection = CursorModelState._computeSelection(this.selectionStart, this.position); - } - - public withSelectionStartLeftoverVisibleColumns(selectionStartLeftoverVisibleColumns: number): CursorModelState { - return new CursorModelState( - this.selectionStart, - selectionStartLeftoverVisibleColumns, - this.position, - this.leftoverVisibleColumns - ); - } - - public withSelectionStart(selectionStart: Range): CursorModelState { - return new CursorModelState( - selectionStart, - 0, - this.position, - this.leftoverVisibleColumns - ); - } - - public collapse(): CursorModelState { - return new CursorModelState( - new Range(this.position.lineNumber, this.position.column, this.position.lineNumber, this.position.column), - 0, - this.position, - 0 - ); - } - - public move(inSelectionMode: boolean, position: Position, leftoverVisibleColumns: number): CursorModelState { - if (inSelectionMode) { - // move just position - return new CursorModelState( - this.selectionStart, - this.selectionStartLeftoverVisibleColumns, - position, - leftoverVisibleColumns - ); - } else { - // move everything - return new CursorModelState( - new Range(position.lineNumber, position.column, position.lineNumber, position.column), - leftoverVisibleColumns, - position, - leftoverVisibleColumns - ); - } - } - - private static _computeSelection(selectionStart: Range, position: Position): Selection { - let startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number; - if (selectionStart.isEmpty()) { - startLineNumber = selectionStart.startLineNumber; - startColumn = selectionStart.startColumn; - endLineNumber = position.lineNumber; - endColumn = position.column; - } else { - if (position.isBeforeOrEqual(selectionStart.getStartPosition())) { - startLineNumber = selectionStart.endLineNumber; - startColumn = selectionStart.endColumn; - endLineNumber = position.lineNumber; - endColumn = position.column; - } else { - startLineNumber = selectionStart.startLineNumber; - startColumn = selectionStart.startColumn; - endLineNumber = position.lineNumber; - endColumn = position.column; - } - } - return new Selection( - startLineNumber, - startColumn, - endLineNumber, - endColumn - ); - } -} export interface IOneCursor { - readonly modelState: CursorModelState; - readonly viewState: CursorModelState; - readonly config: CursorMoveConfiguration; + readonly modelState: SingleCursorState; + readonly viewState: SingleCursorState; + readonly config: CursorConfiguration; +} + +export class MoveOperationResult { + + readonly modelState: SingleCursorState; + readonly viewState: SingleCursorState; + readonly ensureInEditableRange: boolean; + readonly reason: editorCommon.CursorChangeReason; + + constructor( + modelState: SingleCursorState, + viewState: SingleCursorState, + ensureInEditableRange: boolean, + reason: editorCommon.CursorChangeReason + ) { + this.modelState = modelState; + this.viewState = viewState; + this.ensureInEditableRange = ensureInEditableRange; + this.reason = reason; + } + } export class OneCursor implements IOneCursor { @@ -233,19 +110,18 @@ export class OneCursor implements IOneCursor { // --- contextual state private readonly editorId: number; public readonly model: editorCommon.IModel; - public readonly viewModel: ICursorMoveHelperModel; - public readonly configuration: editorCommon.IConfiguration; + public readonly viewModel: ICursorSimpleModel; + private readonly configuration: editorCommon.IConfiguration; private readonly viewModelHelper: IViewModelHelper; private readonly _modelOptionsListener: IDisposable; private readonly _configChangeListener: IDisposable; - public modeConfiguration: IModeConfiguration; - private helper: CursorHelper; - public config: CursorMoveConfiguration; + private modeConfiguration: IModeConfiguration; + public config: CursorConfiguration; - public modelState: CursorModelState; - public viewState: CursorModelState; + public modelState: SingleCursorState; + public viewState: SingleCursorState; // --- bracket match decorations private bracketDecorations: string[]; @@ -266,36 +142,77 @@ export class OneCursor implements IOneCursor { this.configuration = configuration; this.modeConfiguration = modeConfiguration; this.viewModelHelper = viewModelHelper; - this.viewModel = viewModelHelper.viewModel; + this.viewModel = this.viewModelHelper.viewModel; - this._recreateCursorHelper(); + this._recreateCursorConfig(); - this._modelOptionsListener = model.onDidChangeOptions(() => this._recreateCursorHelper()); + this._modelOptionsListener = model.onDidChangeOptions(() => this._recreateCursorConfig()); this._configChangeListener = this.configuration.onDidChange((e) => { - if (e.layoutInfo) { - // due to pageSize - this._recreateCursorHelper(); + if (CursorConfiguration.shouldRecreate(e)) { + this._recreateCursorConfig(); } }); this.bracketDecorations = []; this._setState( - new CursorModelState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0), - new CursorModelState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0) + new SingleCursorState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0), + new SingleCursorState(new Range(1, 1, 1, 1), 0, new Position(1, 1), 0), + false ); } - private _recreateCursorHelper(): void { - this.config = new CursorMoveConfiguration( - this.model.getOptions().tabSize, - this.getPageSize() - ); - this.helper = new CursorHelper(this.model, this.configuration, this.config); + /** + * Sometimes, the line mapping changes and the stored view position is stale. + */ + public ensureValidState(): void { + this._setState(this.modelState, this.viewState, false); } - private _setState(modelState: CursorModelState, viewState: CursorModelState): void { + private _recreateCursorConfig(): void { + this.config = new CursorConfiguration( + this.model.getOneIndent(), + this.model.getOptions(), + this.configuration, + this.modeConfiguration + ); + } + + private _ensureInEditableRange(position: Position): Position { + let editableRange = this.model.getEditableRange(); + + if (position.lineNumber < editableRange.startLineNumber || (position.lineNumber === editableRange.startLineNumber && position.column < editableRange.startColumn)) { + return new Position(editableRange.startLineNumber, editableRange.startColumn); + } else if (position.lineNumber > editableRange.endLineNumber || (position.lineNumber === editableRange.endLineNumber && position.column > editableRange.endColumn)) { + return new Position(editableRange.endLineNumber, editableRange.endColumn); + } + return position; + } + + private _setState(modelState: SingleCursorState, viewState: SingleCursorState, ensureInEditableRange: boolean): void { + // Validate new model state + let selectionStart = this.model.validateRange(modelState.selectionStart); + let selectionStartLeftoverVisibleColumns = modelState.selectionStart.equalsRange(selectionStart) ? modelState.selectionStartLeftoverVisibleColumns : 0; + + let position = this.model.validatePosition(modelState.position); + if (ensureInEditableRange) { + position = this._ensureInEditableRange(position); + } + let leftoverVisibleColumns = modelState.position.equals(position) ? modelState.leftoverVisibleColumns : 0; + + modelState = new SingleCursorState(selectionStart, selectionStartLeftoverVisibleColumns, position, leftoverVisibleColumns); + + // Validate new view state + let viewSelectionStart = this.viewModelHelper.validateViewRange(viewState.selectionStart, modelState.selectionStart); + let viewPosition = this.viewModelHelper.validateViewPosition(viewState.position, modelState.position); + viewState = new SingleCursorState(viewSelectionStart, selectionStartLeftoverVisibleColumns, viewPosition, leftoverVisibleColumns); + + if (this.modelState && this.viewState && this.modelState.equals(modelState) && this.viewState.equals(viewState)) { + // No-op, early return + return; + } + this.modelState = modelState; this.viewState = viewState; @@ -333,29 +250,32 @@ export class OneCursor implements IOneCursor { selectionStart = new Range(position.lineNumber, position.column, position.lineNumber, position.column); } - let viewPosition = this.viewModelHelper.validateViewPosition(state.viewPosition.lineNumber, state.viewPosition.column, position); + let viewPosition = this.viewModelHelper.validateViewPosition(new Position(state.viewPosition.lineNumber, state.viewPosition.column), position); let viewSelectionStart: Range; if (state.viewSelectionStart) { - viewSelectionStart = this.viewModelHelper.validateViewRange(state.viewSelectionStart.startLineNumber, state.viewSelectionStart.startColumn, state.viewSelectionStart.endLineNumber, state.viewSelectionStart.endColumn, selectionStart); + viewSelectionStart = this.viewModelHelper.validateViewRange(new Range(state.viewSelectionStart.startLineNumber, state.viewSelectionStart.startColumn, state.viewSelectionStart.endLineNumber, state.viewSelectionStart.endColumn), selectionStart); } else { viewSelectionStart = this.viewModelHelper.convertModelRangeToViewRange(selectionStart); } this._setState( - new CursorModelState(selectionStart, state.selectionStartLeftoverVisibleColumns, position, state.leftoverVisibleColumns), - new CursorModelState(viewSelectionStart, state.selectionStartLeftoverVisibleColumns, viewPosition, state.leftoverVisibleColumns) + new SingleCursorState(selectionStart, state.selectionStartLeftoverVisibleColumns, position, state.leftoverVisibleColumns), + new SingleCursorState(viewSelectionStart, state.selectionStartLeftoverVisibleColumns, viewPosition, state.leftoverVisibleColumns), + false ); } public updateModeConfiguration(modeConfiguration: IModeConfiguration): void { this.modeConfiguration = modeConfiguration; + this._recreateCursorConfig(); } public duplicate(): OneCursor { let result = new OneCursor(this.editorId, this.model, this.configuration, this.modeConfiguration, this.viewModelHelper); result._setState( this.modelState, - this.viewState + this.viewState, + false ); return result; } @@ -404,16 +324,17 @@ export class OneCursor implements IOneCursor { let viewSelectionStart: Position; if (viewSelection) { - viewPosition = this.viewModelHelper.validateViewPosition(viewSelection.positionLineNumber, viewSelection.positionColumn, position); - viewSelectionStart = this.viewModelHelper.validateViewPosition(viewSelection.selectionStartLineNumber, viewSelection.selectionStartColumn, selectionStart); + viewPosition = this.viewModelHelper.validateViewPosition(new Position(viewSelection.positionLineNumber, viewSelection.positionColumn), position); + viewSelectionStart = this.viewModelHelper.validateViewPosition(new Position(viewSelection.selectionStartLineNumber, viewSelection.selectionStartColumn), selectionStart); } else { viewPosition = this.viewModelHelper.convertModelPositionToViewPosition(position.lineNumber, position.column); viewSelectionStart = this.viewModelHelper.convertModelPositionToViewPosition(selectionStart.lineNumber, selectionStart.column); } this._setState( - new CursorModelState(new Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column), 0, position, 0), - new CursorModelState(new Range(viewSelectionStart.lineNumber, viewSelectionStart.column, viewSelectionStart.lineNumber, viewSelectionStart.column), 0, viewPosition, 0) + new SingleCursorState(new Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column), 0, position, 0), + new SingleCursorState(new Range(viewSelectionStart.lineNumber, viewSelectionStart.column, viewSelectionStart.lineNumber, viewSelectionStart.column), 0, viewPosition, 0), + false ); } @@ -422,14 +343,16 @@ export class OneCursor implements IOneCursor { public setSelectionStart(range: Range): void { this._setState( this.modelState.withSelectionStart(range), - this.viewState.withSelectionStart(this.viewModelHelper.convertModelRangeToViewRange(range)) + this.viewState.withSelectionStart(this.viewModelHelper.convertModelRangeToViewRange(range)), + false ); } public collapseSelection(): void { this._setState( this.modelState.collapse(), - this.viewState.collapse() + this.viewState.collapse(), + false ); } @@ -444,33 +367,17 @@ export class OneCursor implements IOneCursor { } private _move(inSelectionMode: boolean, lineNumber: number, column: number, viewLineNumber: number, viewColumn: number, leftoverVisibleColumns: number, ensureInEditableRange: boolean): void { - - if (ensureInEditableRange) { - let editableRange = this.model.getEditableRange(); - - if (lineNumber < editableRange.startLineNumber || (lineNumber === editableRange.startLineNumber && column < editableRange.startColumn)) { - lineNumber = editableRange.startLineNumber; - column = editableRange.startColumn; - - let viewPosition = this.viewModelHelper.convertModelPositionToViewPosition(lineNumber, column); - viewLineNumber = viewPosition.lineNumber; - viewColumn = viewPosition.column; - } else if (lineNumber > editableRange.endLineNumber || (lineNumber === editableRange.endLineNumber && column > editableRange.endColumn)) { - lineNumber = editableRange.endLineNumber; - column = editableRange.endColumn; - - let viewPosition = this.viewModelHelper.convertModelPositionToViewPosition(lineNumber, column); - viewLineNumber = viewPosition.lineNumber; - viewColumn = viewPosition.column; - } - } - this._setState( this.modelState.move(inSelectionMode, new Position(lineNumber, column), leftoverVisibleColumns), - this.viewState.move(inSelectionMode, new Position(viewLineNumber, viewColumn), leftoverVisibleColumns) + this.viewState.move(inSelectionMode, new Position(viewLineNumber, viewColumn), leftoverVisibleColumns), + ensureInEditableRange ); } + public setState(modelState: SingleCursorState, viewState: SingleCursorState, ensureInEditableRange: boolean): void { + this._setState(modelState, viewState, ensureInEditableRange); + } + private _recoverSelectionFromMarkers(): Selection { let start = this.model._getMarker(this._selStartMarker); let end = this.model._getMarker(this._selEndMarker); @@ -498,8 +405,9 @@ export class OneCursor implements IOneCursor { let viewPosition = this.viewModelHelper.convertViewToModelPosition(position.lineNumber, position.column); this._setState( - new CursorModelState(selectionStart, 0, position, 0), - new CursorModelState(viewSelectionStart, 0, viewPosition, 0) + new SingleCursorState(selectionStart, 0, position, 0), + new SingleCursorState(viewSelectionStart, 0, viewPosition, 0), + false ); return true; @@ -509,25 +417,14 @@ export class OneCursor implements IOneCursor { // -------------------- START reading API - public getPageSize(): number { - let c = this.configuration.editor; - return Math.floor(c.layoutInfo.height / c.fontInfo.lineHeight) - 2; - } - - public getValidViewPosition(): Position { - return this.viewModelHelper.validateViewPosition(this.viewState.position.lineNumber, this.viewState.position.column, this.modelState.position); - } - - public hasSelection(): boolean { - return (!this.modelState.selection.isEmpty() || !this.modelState.selectionStart.isEmpty()); - } public getBracketsDecorations(): string[] { return this.bracketDecorations; } public setSelectionStartLeftoverVisibleColumns(value: number): void { this._setState( this.modelState.withSelectionStartLeftoverVisibleColumns(value), - this.viewState.withSelectionStartLeftoverVisibleColumns(value) + this.viewState.withSelectionStartLeftoverVisibleColumns(value), + false ); } @@ -536,15 +433,16 @@ export class OneCursor implements IOneCursor { return this.model.validatePosition(position); } public validateViewPosition(viewLineNumber: number, viewColumn: number, modelPosition: Position): Position { - return this.viewModelHelper.validateViewPosition(viewLineNumber, viewColumn, modelPosition); - } - public convertViewToModelPosition(lineNumber: number, column: number): editorCommon.IPosition { - return this.viewModelHelper.convertViewToModelPosition(lineNumber, column); + return this.viewModelHelper.validateViewPosition(new Position(viewLineNumber, viewColumn), modelPosition); } public convertViewSelectionToModelSelection(viewSelection: Selection): Selection { return this.viewModelHelper.convertViewSelectionToModelSelection(viewSelection); } - public convertModelPositionToViewPosition(lineNumber: number, column: number): editorCommon.IPosition { + public convertViewToModelPosition(lineNumber: number, column: number): Position { + return this.viewModelHelper.convertViewToModelPosition(lineNumber, column); + } + + public convertModelPositionToViewPosition(lineNumber: number, column: number): Position { return this.viewModelHelper.convertModelPositionToViewPosition(lineNumber, column); } @@ -596,25 +494,10 @@ export class OneCursor implements IOneCursor { let visibleLineNumber = visibleRange.endLineNumber - (lineFromBottom - 1); return visibleLineNumber > visibleRange.startLineNumber ? visibleLineNumber : this.getLineFromViewPortTop(); } - public findPreviousWordOnLine(position: Position): IFindWordResult { - return this.helper.findPreviousWordOnLine(position); - } - public findNextWordOnLine(position: Position): IFindWordResult { - return this.helper.findNextWordOnLine(position); - } - public getColumnAtEndOfLine(lineNumber: number, column: number): number { - return this.helper.getColumnAtEndOfLine(this.model, lineNumber, column); - } - public getVisibleColumnFromColumn(lineNumber: number, column: number): number { - return this.helper.visibleColumnFromColumn(this.model, lineNumber, column); - } - public getViewVisibleColumnFromColumn(viewLineNumber: number, viewColumn: number): number { - return this.helper.visibleColumnFromColumn(this.viewModelHelper.viewModel, viewLineNumber, viewColumn); - } // -- view public isLastLineVisibleInViewPort(): boolean { - return this.viewModelHelper.viewModel.getLineCount() <= this.getCompletelyVisibleViewLinesRangeInViewport().getEndPosition().lineNumber; + return this.viewModel.getLineCount() <= this.getCompletelyVisibleViewLinesRangeInViewport().getEndPosition().lineNumber; } public getCompletelyVisibleViewLinesRangeInViewport(): Range { return this.viewModelHelper.getCurrentCompletelyVisibleViewLinesRangeInViewport(); @@ -626,61 +509,27 @@ export class OneCursor implements IOneCursor { visibleRange.startLineNumber, visibleRange.startColumn, visibleRange.endLineNumber - 1, - this.viewModelHelper.viewModel.getLineLastNonWhitespaceColumn(visibleRange.endLineNumber - 1) + this.viewModel.getLineLastNonWhitespaceColumn(visibleRange.endLineNumber - 1) ); } return visibleRange; } - public getViewLineCount(): number { - return this.viewModelHelper.viewModel.getLineCount(); - } - public getViewLineMaxColumn(lineNumber: number): number { - return this.viewModelHelper.viewModel.getLineMaxColumn(lineNumber); - } - public getViewLineMinColumn(lineNumber: number): number { - return this.viewModelHelper.viewModel.getLineMinColumn(lineNumber); - } - public getViewLineCenterColumn(lineNumber: number): number { - return Math.round((this.getViewLineMaxColumn(lineNumber) + this.getViewLineMinColumn(lineNumber)) / 2); - } - public getViewLineSize(lineNumber: number): number { - return this.getViewLineMaxColumn(lineNumber) - this.getViewLineMinColumn(lineNumber); - } - public getViewHalfLineSize(lineNumber: number): number { - return Math.round(this.getViewLineSize(lineNumber) / 2); - } - public getViewLineFirstNonWhiteSpaceColumn(lineNumber: number): number { - return this.viewModelHelper.viewModel.getLineFirstNonWhitespaceColumn(lineNumber); - } - public getViewLineLastNonWhiteSpaceColumn(lineNumber: number): number { - return this.viewModelHelper.viewModel.getLineLastNonWhitespaceColumn(lineNumber); - } public getColumnAtBeginningOfViewLine(lineNumber: number, column: number): number { - return this.helper.getColumnAtBeginningOfLine(this.viewModelHelper.viewModel, lineNumber, column); + return CursorMoveHelper.getColumnAtBeginningOfLine(this.viewModel, lineNumber, column); } public getColumnAtEndOfViewLine(lineNumber: number, column: number): number { - return this.helper.getColumnAtEndOfLine(this.viewModelHelper.viewModel, lineNumber, column); - } - public columnSelect(fromViewLineNumber: number, fromViewVisibleColumn: number, toViewLineNumber: number, toViewVisibleColumn: number): IColumnSelectResult { - let r = this.helper.columnSelect(this.viewModelHelper.viewModel, fromViewLineNumber, fromViewVisibleColumn, toViewLineNumber, toViewVisibleColumn); - return { - reversed: r.reversed, - viewSelections: r.viewSelections, - selections: r.viewSelections.map(sel => this.convertViewSelectionToModelSelection(sel)), - toLineNumber: toViewLineNumber, - toVisualColumn: toViewVisibleColumn - }; + return CursorMoveHelper.getColumnAtEndOfLine(this.viewModel, lineNumber, column); } public getNearestRevealViewPositionInViewport(): Position { const position = this.viewState.position; const revealRange = this.getRevealViewLinesRangeInViewport(); if (position.lineNumber < revealRange.startLineNumber) { - return new Position(revealRange.startLineNumber, this.viewModelHelper.viewModel.getLineFirstNonWhitespaceColumn(revealRange.startLineNumber)); + return new Position(revealRange.startLineNumber, this.viewModel.getLineFirstNonWhitespaceColumn(revealRange.startLineNumber)); } if (position.lineNumber > revealRange.endLineNumber) { - return new Position(revealRange.endLineNumber, this.viewModelHelper.viewModel.getLineFirstNonWhitespaceColumn(revealRange.endLineNumber)); + return new Position(revealRange.endLineNumber, this.viewModel.getLineFirstNonWhitespaceColumn(revealRange.endLineNumber)); } return position; @@ -736,50 +585,54 @@ export class OneCursorOp { return true; } + private static _getViewHalfLineSize(cursor: OneCursor, lineNumber: number): number { + return Math.round((cursor.viewModel.getLineMaxColumn(lineNumber) - cursor.viewModel.getLineMinColumn(lineNumber)) / 2); + } + public static move(cursor: OneCursor, moveParams: CursorMoveArguments, eventSource: string, ctx: IOneCursorOperationContext): boolean { if (!moveParams.to) { illegalArgument('to'); } let inSelectionMode = !!moveParams.select; - let validatedViewPosition = cursor.getValidViewPosition(); + let validatedViewPosition = cursor.viewState.position; let viewLineNumber = validatedViewPosition.lineNumber; - let viewColumn; + let viewColumn: number; switch (moveParams.to) { case editorCommon.CursorMovePosition.Left: - return this.moveLeft(cursor, inSelectionMode, editorCommon.CursorMoveByUnit.HalfLine === moveParams.by ? cursor.getViewHalfLineSize(viewLineNumber) : moveParams.value, ctx); + return this._moveLeft(cursor, inSelectionMode, editorCommon.CursorMoveByUnit.HalfLine === moveParams.by ? this._getViewHalfLineSize(cursor, viewLineNumber) : moveParams.value, ctx); case editorCommon.CursorMovePosition.Right: - return this.moveRight(cursor, inSelectionMode, editorCommon.CursorMoveByUnit.HalfLine === moveParams.by ? cursor.getViewHalfLineSize(viewLineNumber) : moveParams.value, ctx); + return this._moveRight(cursor, inSelectionMode, editorCommon.CursorMoveByUnit.HalfLine === moveParams.by ? this._getViewHalfLineSize(cursor, viewLineNumber) : moveParams.value, ctx); case editorCommon.CursorMovePosition.Up: - return this.moveUp(cursor, moveParams, ctx); + return this._moveUp(cursor, moveParams, ctx); case editorCommon.CursorMovePosition.Down: - return this.moveDown(cursor, moveParams, ctx); + return this._moveDown(cursor, moveParams, ctx); case editorCommon.CursorMovePosition.WrappedLineStart: - viewColumn = cursor.getViewLineMinColumn(viewLineNumber); + viewColumn = cursor.viewModel.getLineMinColumn(viewLineNumber); break; case editorCommon.CursorMovePosition.WrappedLineFirstNonWhitespaceCharacter: - viewColumn = cursor.getViewLineFirstNonWhiteSpaceColumn(viewLineNumber); + viewColumn = cursor.viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber); break; case editorCommon.CursorMovePosition.WrappedLineColumnCenter: - viewColumn = cursor.getViewLineCenterColumn(viewLineNumber); + viewColumn = Math.round((cursor.viewModel.getLineMaxColumn(viewLineNumber) + cursor.viewModel.getLineMinColumn(viewLineNumber)) / 2); break; case editorCommon.CursorMovePosition.WrappedLineEnd: - viewColumn = cursor.getViewLineMaxColumn(viewLineNumber); + viewColumn = cursor.viewModel.getLineMaxColumn(viewLineNumber); break; case editorCommon.CursorMovePosition.WrappedLineLastNonWhitespaceCharacter: - viewColumn = cursor.getViewLineLastNonWhiteSpaceColumn(viewLineNumber); + viewColumn = cursor.viewModel.getLineLastNonWhitespaceColumn(viewLineNumber); break; case editorCommon.CursorMovePosition.ViewPortTop: viewLineNumber = cursor.convertModelPositionToViewPosition(cursor.getLineFromViewPortTop(moveParams.value), 1).lineNumber; - viewColumn = cursor.getViewLineFirstNonWhiteSpaceColumn(viewLineNumber); + viewColumn = cursor.viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber); break; case editorCommon.CursorMovePosition.ViewPortBottom: viewLineNumber = cursor.convertModelPositionToViewPosition(cursor.getLineFromViewPortBottom(moveParams.value), 1).lineNumber;; - viewColumn = cursor.getViewLineFirstNonWhiteSpaceColumn(viewLineNumber); + viewColumn = cursor.viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber); break; case editorCommon.CursorMovePosition.ViewPortCenter: viewLineNumber = cursor.convertModelPositionToViewPosition(cursor.getCenterLineInViewPort(), 1).lineNumber;; - viewColumn = cursor.getViewLineFirstNonWhiteSpaceColumn(viewLineNumber); + viewColumn = cursor.viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber); break; case editorCommon.CursorMovePosition.ViewPortIfOutside: const position = cursor.getNearestRevealViewPositionInViewport(); @@ -794,191 +647,68 @@ export class OneCursorOp { return true; } - private static _columnSelectOp(cursor: OneCursor, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - let viewStartSelection = cursor.viewState.selection; - let fromVisibleColumn = cursor.getViewVisibleColumnFromColumn(viewStartSelection.selectionStartLineNumber, viewStartSelection.selectionStartColumn); - - return cursor.columnSelect(viewStartSelection.selectionStartLineNumber, fromVisibleColumn, toViewLineNumber, toViewVisualColumn); - } - - public static columnSelectMouse(cursor: OneCursor, position: editorCommon.IPosition, viewPosition: editorCommon.IPosition, toViewVisualColumn: number): IColumnSelectResult { - let validatedPosition = cursor.model.validatePosition(position); - let validatedViewPosition: editorCommon.IPosition; - if (viewPosition) { - validatedViewPosition = cursor.validateViewPosition(viewPosition.lineNumber, viewPosition.column, validatedPosition); - } else { - validatedViewPosition = cursor.convertModelPositionToViewPosition(validatedPosition.lineNumber, validatedPosition.column); - } - - return this._columnSelectOp(cursor, validatedViewPosition.lineNumber, toViewVisualColumn); - } - - public static columnSelectLeft(cursor: OneCursor, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - if (toViewVisualColumn > 1) { - toViewVisualColumn--; - } - - return this._columnSelectOp(cursor, toViewLineNumber, toViewVisualColumn); - } - - public static columnSelectRight(cursor: OneCursor, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - - let maxVisualViewColumn = 0; - let minViewLineNumber = Math.min(cursor.viewState.position.lineNumber, toViewLineNumber); - let maxViewLineNumber = Math.max(cursor.viewState.position.lineNumber, toViewLineNumber); - for (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) { - let lineMaxViewColumn = cursor.getViewLineMaxColumn(lineNumber); - let lineMaxVisualViewColumn = cursor.getViewVisibleColumnFromColumn(lineNumber, lineMaxViewColumn); - maxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn); - } - - if (toViewVisualColumn < maxVisualViewColumn) { - toViewVisualColumn++; - } - - return this._columnSelectOp(cursor, toViewLineNumber, toViewVisualColumn); - } - - public static columnSelectUp(isPaged: boolean, cursor: OneCursor, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - let linesCount = isPaged ? cursor.getPageSize() : 1; - - toViewLineNumber -= linesCount; - if (toViewLineNumber < 1) { - toViewLineNumber = 1; - } - - return this._columnSelectOp(cursor, toViewLineNumber, toViewVisualColumn); - } - - public static columnSelectDown(isPaged: boolean, cursor: OneCursor, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - let linesCount = isPaged ? cursor.getPageSize() : 1; - - toViewLineNumber += linesCount; - if (toViewLineNumber > cursor.getViewLineCount()) { - toViewLineNumber = cursor.getViewLineCount(); - } - - return this._columnSelectOp(cursor, toViewLineNumber, toViewVisualColumn); - } - - public static moveLeft(cursor: OneCursor, inSelectionMode: boolean, noOfColumns: number = 1, ctx: IOneCursorOperationContext): boolean { - let viewLineNumber: number, - viewColumn: number; - - if (cursor.hasSelection() && !inSelectionMode) { - // If we are in selection mode, move left without selection cancels selection and puts cursor at the beginning of the selection - let viewSelection = cursor.viewState.selection; - let viewSelectionStart = cursor.validateViewPosition(viewSelection.startLineNumber, viewSelection.startColumn, cursor.modelState.selection.getStartPosition()); - viewLineNumber = viewSelectionStart.lineNumber; - viewColumn = viewSelectionStart.column; - } else { - let validatedViewPosition = cursor.getValidViewPosition(); - let r = CursorMove.left(cursor.config, cursor.viewModel, validatedViewPosition.lineNumber, validatedViewPosition.column - (noOfColumns - 1)); - viewLineNumber = r.lineNumber; - viewColumn = r.column; - } - - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveViewPosition(inSelectionMode, viewLineNumber, viewColumn, 0, true); + private static _applyMoveOperationResult(cursor: OneCursor, ctx: IOneCursorOperationContext, r: MoveOperationResult): boolean { + ctx.cursorPositionChangeReason = r.reason; + cursor.setState(r.modelState, r.viewState, r.ensureInEditableRange); return true; } + private static _fromModelCursorState(cursor: OneCursor, r: SingleMoveOperationResult): MoveOperationResult { + let viewSelectionStart1 = cursor.convertModelPositionToViewPosition(r.state.selectionStart.startLineNumber, r.state.selectionStart.startColumn); + let viewSelectionStart2 = cursor.convertModelPositionToViewPosition(r.state.selectionStart.endLineNumber, r.state.selectionStart.endColumn); + let viewSelectionStart = new Range(viewSelectionStart1.lineNumber, viewSelectionStart1.column, viewSelectionStart2.lineNumber, viewSelectionStart2.column); + let viewPosition = cursor.convertModelPositionToViewPosition(r.state.position.lineNumber, r.state.position.column); + return new MoveOperationResult( + r.state, + new SingleCursorState(viewSelectionStart, r.state.selectionStartLeftoverVisibleColumns, viewPosition, r.state.leftoverVisibleColumns), + r.ensureInEditableRange, + r.reason + ); + } + + private static _fromViewCursorState(cursor: OneCursor, r: SingleMoveOperationResult): MoveOperationResult { + let selectionStart1 = cursor.convertViewToModelPosition(r.state.selectionStart.startLineNumber, r.state.selectionStart.startColumn); + let selectionStart2 = cursor.convertViewToModelPosition(r.state.selectionStart.endLineNumber, r.state.selectionStart.endColumn); + let selectionStart = new Range(selectionStart1.lineNumber, selectionStart1.column, selectionStart2.lineNumber, selectionStart2.column); + let position = cursor.convertViewToModelPosition(r.state.position.lineNumber, r.state.position.column); + return new MoveOperationResult( + new SingleCursorState(selectionStart, r.state.selectionStartLeftoverVisibleColumns, position, r.state.leftoverVisibleColumns), + r.state, + r.ensureInEditableRange, + r.reason + ); + } + + private static _moveLeft(cursor: OneCursor, inSelectionMode: boolean, noOfColumns: number = 1, ctx: IOneCursorOperationContext): boolean { + return this._applyMoveOperationResult( + cursor, ctx, + this._fromViewCursorState(cursor, MoveOperations.moveLeft(cursor.config, cursor.viewModel, cursor.viewState, inSelectionMode, noOfColumns)) + ); + } + public static moveWordLeft(cursor: OneCursor, inSelectionMode: boolean, wordNavigationType: WordNavigationType, ctx: IOneCursorOperationContext): boolean { - let position = cursor.modelState.position; - let lineNumber = position.lineNumber; - let column = position.column; - - if (column === 1) { - if (lineNumber > 1) { - lineNumber = lineNumber - 1; - column = cursor.model.getLineMaxColumn(lineNumber); - } - } - - let prevWordOnLine = cursor.findPreviousWordOnLine(new Position(lineNumber, column)); - - if (wordNavigationType === WordNavigationType.WordStart) { - if (prevWordOnLine) { - column = prevWordOnLine.start + 1; - } else { - column = 1; - } - } else { - if (prevWordOnLine && column <= prevWordOnLine.end + 1) { - prevWordOnLine = cursor.findPreviousWordOnLine(new Position(lineNumber, prevWordOnLine.start + 1)); - } - if (prevWordOnLine) { - column = prevWordOnLine.end + 1; - } else { - column = 1; - } - } - - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveModelPosition(inSelectionMode, lineNumber, column, 0, true); - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromModelCursorState(cursor, WordOperations.moveWordLeft(cursor.config, cursor.model, cursor.modelState, inSelectionMode, wordNavigationType)) + ); } - public static moveRight(cursor: OneCursor, inSelectionMode: boolean, noOfColumns: number = 1, ctx: IOneCursorOperationContext): boolean { - let viewLineNumber: number, - viewColumn: number; - - if (cursor.hasSelection() && !inSelectionMode) { - // If we are in selection mode, move right without selection cancels selection and puts cursor at the end of the selection - let viewSelection = cursor.viewState.selection; - let viewSelectionEnd = cursor.validateViewPosition(viewSelection.endLineNumber, viewSelection.endColumn, cursor.modelState.selection.getEndPosition()); - viewLineNumber = viewSelectionEnd.lineNumber; - viewColumn = viewSelectionEnd.column; - } else { - let validatedViewPosition = cursor.getValidViewPosition(); - let r = CursorMove.right(cursor.config, cursor.viewModel, validatedViewPosition.lineNumber, validatedViewPosition.column + (noOfColumns - 1)); - viewLineNumber = r.lineNumber; - viewColumn = r.column; - } - - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveViewPosition(inSelectionMode, viewLineNumber, viewColumn, 0, true); - return true; + private static _moveRight(cursor: OneCursor, inSelectionMode: boolean, noOfColumns: number = 1, ctx: IOneCursorOperationContext): boolean { + return this._applyMoveOperationResult( + cursor, ctx, + this._fromViewCursorState(cursor, MoveOperations.moveRight(cursor.config, cursor.viewModel, cursor.viewState, inSelectionMode, noOfColumns)) + ); } public static moveWordRight(cursor: OneCursor, inSelectionMode: boolean, wordNavigationType: WordNavigationType, ctx: IOneCursorOperationContext): boolean { - let position = cursor.modelState.position; - let lineNumber = position.lineNumber; - let column = position.column; - - if (column === cursor.model.getLineMaxColumn(lineNumber)) { - if (lineNumber < cursor.model.getLineCount()) { - lineNumber = lineNumber + 1; - column = 1; - } - } - - let nextWordOnLine = cursor.findNextWordOnLine(new Position(lineNumber, column)); - - if (wordNavigationType === WordNavigationType.WordEnd) { - if (nextWordOnLine) { - column = nextWordOnLine.end + 1; - } else { - column = cursor.model.getLineMaxColumn(lineNumber); - } - } else { - if (nextWordOnLine && column >= nextWordOnLine.start + 1) { - nextWordOnLine = cursor.findNextWordOnLine(new Position(lineNumber, nextWordOnLine.end + 1)); - } - if (nextWordOnLine) { - column = nextWordOnLine.start + 1; - } else { - column = cursor.model.getLineMaxColumn(lineNumber); - } - } - - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveModelPosition(inSelectionMode, lineNumber, column, 0, true); - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromModelCursorState(cursor, WordOperations.moveWordRight(cursor.config, cursor.model, cursor.modelState, inSelectionMode, wordNavigationType)) + ); } - public static moveDown(cursor: OneCursor, moveArguments: CursorMoveArguments, ctx: IOneCursorOperationContext): boolean { - let linesCount = (moveArguments.isPaged ? (moveArguments.pageSize || cursor.getPageSize()) : moveArguments.value) || 1; + private static _moveDown(cursor: OneCursor, moveArguments: CursorMoveArguments, ctx: IOneCursorOperationContext): boolean { + let linesCount = (moveArguments.isPaged ? (moveArguments.pageSize || cursor.config.pageSize) : moveArguments.value) || 1; if (editorCommon.CursorMoveByUnit.WrappedLine === moveArguments.by) { return this._moveDownByViewLines(cursor, moveArguments.select, linesCount, ctx); } @@ -986,67 +716,28 @@ export class OneCursorOp { } private static _moveDownByViewLines(cursor: OneCursor, inSelectionMode: boolean, linesCount: number, ctx: IOneCursorOperationContext): boolean { - let viewLineNumber: number, - viewColumn: number; - - if (cursor.hasSelection() && !inSelectionMode) { - // If we are in selection mode, move down acts relative to the end of selection - let viewSelection = cursor.viewState.selection; - let viewSelectionEnd = cursor.validateViewPosition(viewSelection.endLineNumber, viewSelection.endColumn, cursor.modelState.selection.getEndPosition()); - viewLineNumber = viewSelectionEnd.lineNumber; - viewColumn = viewSelectionEnd.column; - } else { - let validatedViewPosition = cursor.getValidViewPosition(); - viewLineNumber = validatedViewPosition.lineNumber; - viewColumn = validatedViewPosition.column; - } - - let r = CursorMove.down(cursor.config, cursor.viewModel, viewLineNumber, viewColumn, cursor.viewState.leftoverVisibleColumns, linesCount, true); - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveViewPosition(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns, true); - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromViewCursorState(cursor, MoveOperations.moveDown(cursor.config, cursor.viewModel, cursor.viewState, inSelectionMode, linesCount)) + ); } private static _moveDownByModelLines(cursor: OneCursor, inSelectionMode: boolean, linesCount: number, ctx: IOneCursorOperationContext): boolean { - let lineNumber: number, - column: number; - - if (cursor.hasSelection() && !inSelectionMode) { - // If we are in selection mode, move down acts relative to the end of selection - let selection = cursor.modelState.selection; - lineNumber = selection.endLineNumber; - column = selection.endColumn; - } else { - let position = cursor.modelState.position; - lineNumber = position.lineNumber; - column = position.column; - } - - let r = CursorMove.down(cursor.config, cursor.model, lineNumber, column, cursor.modelState.leftoverVisibleColumns, linesCount, true); - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveModelPosition(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns, true); - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromModelCursorState(cursor, MoveOperations.moveDown(cursor.config, cursor.model, cursor.modelState, inSelectionMode, linesCount)) + ); } public static translateDown(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - - let selection = cursor.viewState.selection; - - let selectionStart = CursorMove.down(cursor.config, cursor.viewModel, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.viewState.selectionStartLeftoverVisibleColumns, 1, false); - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveViewPosition(false, selectionStart.lineNumber, selectionStart.column, cursor.viewState.leftoverVisibleColumns, true); - - let position = CursorMove.down(cursor.config, cursor.viewModel, selection.positionLineNumber, selection.positionColumn, cursor.viewState.leftoverVisibleColumns, 1, false); - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveViewPosition(true, position.lineNumber, position.column, position.leftoverVisibleColumns, true); - - cursor.setSelectionStartLeftoverVisibleColumns(selectionStart.leftoverVisibleColumns); - - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromViewCursorState(cursor, MoveOperations.translateDown(cursor.config, cursor.viewModel, cursor.viewState)) + ); } - public static moveUp(cursor: OneCursor, moveArguments: CursorMoveArguments, ctx: IOneCursorOperationContext): boolean { - let linesCount = (moveArguments.isPaged ? (moveArguments.pageSize || cursor.getPageSize()) : moveArguments.value) || 1; + private static _moveUp(cursor: OneCursor, moveArguments: CursorMoveArguments, ctx: IOneCursorOperationContext): boolean { + let linesCount = (moveArguments.isPaged ? (moveArguments.pageSize || cursor.config.pageSize) : moveArguments.value) || 1; if (editorCommon.CursorMoveByUnit.WrappedLine === moveArguments.by) { return this._moveUpByViewLines(cursor, moveArguments.select, linesCount, ctx); } @@ -1054,70 +745,28 @@ export class OneCursorOp { } private static _moveUpByViewLines(cursor: OneCursor, inSelectionMode: boolean, linesCount: number, ctx: IOneCursorOperationContext): boolean { - - let viewLineNumber: number, - viewColumn: number; - - if (cursor.hasSelection() && !inSelectionMode) { - // If we are in selection mode, move up acts relative to the beginning of selection - let viewSelection = cursor.viewState.selection; - let viewSelectionStart = cursor.validateViewPosition(viewSelection.startLineNumber, viewSelection.startColumn, cursor.modelState.selection.getStartPosition()); - viewLineNumber = viewSelectionStart.lineNumber; - viewColumn = viewSelectionStart.column; - } else { - let validatedViewPosition = cursor.getValidViewPosition(); - viewLineNumber = validatedViewPosition.lineNumber; - viewColumn = validatedViewPosition.column; - } - - let r = CursorMove.up(cursor.config, cursor.viewModel, viewLineNumber, viewColumn, cursor.viewState.leftoverVisibleColumns, linesCount, true); - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveViewPosition(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns, true); - - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromViewCursorState(cursor, MoveOperations.moveUp(cursor.config, cursor.viewModel, cursor.viewState, inSelectionMode, linesCount)) + ); } private static _moveUpByModelLines(cursor: OneCursor, inSelectionMode: boolean, linesCount: number, ctx: IOneCursorOperationContext): boolean { - let lineNumber: number, - column: number; - - if (cursor.hasSelection() && !inSelectionMode) { - // If we are in selection mode, move up acts relative to the beginning of selection - let selection = cursor.modelState.selection; - lineNumber = selection.startLineNumber; - column = selection.startColumn; - } else { - let position = cursor.modelState.position; - lineNumber = position.lineNumber; - column = position.column; - } - - let r = CursorMove.up(cursor.config, cursor.model, lineNumber, column, cursor.modelState.leftoverVisibleColumns, linesCount, true); - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveModelPosition(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns, true); - - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromModelCursorState(cursor, MoveOperations.moveUp(cursor.config, cursor.model, cursor.modelState, inSelectionMode, linesCount)) + ); } public static translateUp(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - - let selection = cursor.viewState.selection; - - let selectionStart = CursorMove.up(cursor.config, cursor.viewModel, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.viewState.selectionStartLeftoverVisibleColumns, 1, false); - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveViewPosition(false, selectionStart.lineNumber, selectionStart.column, cursor.viewState.leftoverVisibleColumns, true); - - let position = CursorMove.up(cursor.config, cursor.viewModel, selection.positionLineNumber, selection.positionColumn, cursor.viewState.leftoverVisibleColumns, 1, false); - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveViewPosition(true, position.lineNumber, position.column, position.leftoverVisibleColumns, true); - - cursor.setSelectionStartLeftoverVisibleColumns(selectionStart.leftoverVisibleColumns); - - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromViewCursorState(cursor, MoveOperations.translateUp(cursor.config, cursor.viewModel, cursor.viewState)) + ); } public static moveToBeginningOfLine(cursor: OneCursor, inSelectionMode: boolean, ctx: IOneCursorOperationContext): boolean { - let validatedViewPosition = cursor.getValidViewPosition(); + let validatedViewPosition = cursor.viewState.position; let viewLineNumber = validatedViewPosition.lineNumber; let viewColumn = validatedViewPosition.column; @@ -1128,7 +777,7 @@ export class OneCursorOp { } public static moveToEndOfLine(cursor: OneCursor, inSelectionMode: boolean, ctx: IOneCursorOperationContext): boolean { - let validatedViewPosition = cursor.getValidViewPosition(); + let validatedViewPosition = cursor.viewState.position; let viewLineNumber = validatedViewPosition.lineNumber; let viewColumn = validatedViewPosition.column; @@ -1147,15 +796,15 @@ export class OneCursorOp { let viewEndLineNumber = viewSel.endLineNumber; let viewEndColumn = viewSel.endColumn; - let viewEndMaxColumn = cursor.getViewLineMaxColumn(viewEndLineNumber); + let viewEndMaxColumn = cursor.viewModel.getLineMaxColumn(viewEndLineNumber); if (viewStartColumn !== 1 || viewEndColumn !== viewEndMaxColumn) { viewStartColumn = 1; viewEndColumn = viewEndMaxColumn; } else { // Expand selection with one more line down - let moveResult = CursorMove.down(cursor.config, cursor.viewModel, viewEndLineNumber, viewEndColumn, 0, 1, true); + let moveResult = MoveOperations.down(cursor.config, cursor.viewModel, viewEndLineNumber, viewEndColumn, 0, 1, true); viewEndLineNumber = moveResult.lineNumber; - viewEndColumn = cursor.getViewLineMaxColumn(viewEndLineNumber); + viewEndColumn = cursor.viewModel.getLineMaxColumn(viewEndLineNumber); } cursor.moveViewPosition(false, viewStartLineNumber, viewStartColumn, 0, true); @@ -1164,18 +813,17 @@ export class OneCursorOp { } public static moveToBeginningOfBuffer(cursor: OneCursor, inSelectionMode: boolean, ctx: IOneCursorOperationContext): boolean { - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveModelPosition(inSelectionMode, 1, 1, 0, true); - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromModelCursorState(cursor, MoveOperations.moveToBeginningOfBuffer(cursor.config, cursor.model, cursor.modelState, inSelectionMode)) + ); } public static moveToEndOfBuffer(cursor: OneCursor, inSelectionMode: boolean, ctx: IOneCursorOperationContext): boolean { - let lastLineNumber = cursor.model.getLineCount(); - let lastColumn = cursor.model.getLineMaxColumn(lastLineNumber); - - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveModelPosition(inSelectionMode, lastLineNumber, lastColumn, 0, true); - return true; + return this._applyMoveOperationResult( + cursor, ctx, + this._fromModelCursorState(cursor, MoveOperations.moveToEndOfBuffer(cursor.config, cursor.model, cursor.modelState, inSelectionMode)) + ); } public static selectAll(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { @@ -1230,7 +878,7 @@ export class OneCursorOp { ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; ctx.shouldRevealHorizontal = false; - if (!inSelectionMode || !cursor.hasSelection()) { + if (!inSelectionMode || !cursor.modelState.hasSelection()) { // Entering line selection for the first time let selectToLineNumber = position.lineNumber + 1; @@ -1242,7 +890,7 @@ export class OneCursorOp { let selectionStartRange = new Range(position.lineNumber, 1, selectToLineNumber, selectToColumn); cursor.setSelectionStart(selectionStartRange); - cursor.moveModelPosition(cursor.hasSelection(), selectionStartRange.endLineNumber, selectionStartRange.endColumn, 0, false); + cursor.moveModelPosition(cursor.modelState.hasSelection(), selectionStartRange.endLineNumber, selectionStartRange.endColumn, 0, false); return true; } else { @@ -1251,22 +899,22 @@ export class OneCursorOp { if (position.lineNumber < enteringLineNumber) { - cursor.moveViewPosition(cursor.hasSelection(), viewPosition.lineNumber, 1, 0, false); + cursor.moveViewPosition(cursor.modelState.hasSelection(), viewPosition.lineNumber, 1, 0, false); } else if (position.lineNumber > enteringLineNumber) { let selectToViewLineNumber = viewPosition.lineNumber + 1; let selectToViewColumn = 1; - if (selectToViewLineNumber > cursor.getViewLineCount()) { - selectToViewLineNumber = cursor.getViewLineCount(); - selectToViewColumn = cursor.getViewLineMaxColumn(selectToViewLineNumber); + if (selectToViewLineNumber > cursor.viewModel.getLineCount()) { + selectToViewLineNumber = cursor.viewModel.getLineCount(); + selectToViewColumn = cursor.viewModel.getLineMaxColumn(selectToViewLineNumber); } - cursor.moveViewPosition(cursor.hasSelection(), selectToViewLineNumber, selectToViewColumn, 0, false); + cursor.moveViewPosition(cursor.modelState.hasSelection(), selectToViewLineNumber, selectToViewColumn, 0, false); } else { let endPositionOfSelectionStart = cursor.modelState.selectionStart.getEndPosition(); - cursor.moveModelPosition(cursor.hasSelection(), endPositionOfSelectionStart.lineNumber, endPositionOfSelectionStart.column, 0, false); + cursor.moveModelPosition(cursor.modelState.hasSelection(), endPositionOfSelectionStart.lineNumber, endPositionOfSelectionStart.column, 0, false); } @@ -1276,84 +924,15 @@ export class OneCursorOp { } - public static word(cursor: OneCursor, inSelectionMode: boolean, position: editorCommon.IPosition, ctx: IOneCursorOperationContext): boolean { - // TODO@Alex -> select in editable range - - let validatedPosition = cursor.validatePosition(position); - let prevWord = cursor.findPreviousWordOnLine(validatedPosition); - let isInPrevWord = (prevWord && prevWord.wordType === WordType.Regular && prevWord.start < validatedPosition.column - 1 && validatedPosition.column - 1 <= prevWord.end); - let nextWord = cursor.findNextWordOnLine(validatedPosition); - let isInNextWord = (nextWord && nextWord.wordType === WordType.Regular && nextWord.start < validatedPosition.column - 1 && validatedPosition.column - 1 <= nextWord.end); - - let lineNumber: number; - let column: number; - if (!inSelectionMode || !cursor.hasSelection()) { - - let startColumn: number; - let endColumn: number; - - if (isInPrevWord) { - startColumn = prevWord.start + 1; - endColumn = prevWord.end + 1; - } else if (isInNextWord) { - startColumn = nextWord.start + 1; - endColumn = nextWord.end + 1; - } else { - if (prevWord) { - startColumn = prevWord.end + 1; - } else { - startColumn = 1; - } - if (nextWord) { - endColumn = nextWord.start + 1; - } else { - endColumn = cursor.model.getLineMaxColumn(validatedPosition.lineNumber); - } - } - - let selectionStartRange = new Range(validatedPosition.lineNumber, startColumn, validatedPosition.lineNumber, endColumn); - cursor.setSelectionStart(selectionStartRange); - lineNumber = selectionStartRange.endLineNumber; - column = selectionStartRange.endColumn; - } else { - - let startColumn: number; - let endColumn: number; - - if (isInPrevWord) { - startColumn = prevWord.start + 1; - endColumn = prevWord.end + 1; - } else if (isInNextWord) { - startColumn = nextWord.start + 1; - endColumn = nextWord.end + 1; - } else { - startColumn = validatedPosition.column; - endColumn = validatedPosition.column; - } - - lineNumber = validatedPosition.lineNumber; - if (validatedPosition.isBeforeOrEqual(cursor.modelState.selectionStart.getStartPosition())) { - column = startColumn; - let possiblePosition = new Position(lineNumber, column); - if (cursor.modelState.selectionStart.containsPosition(possiblePosition)) { - column = cursor.modelState.selectionStart.endColumn; - } - } else { - column = endColumn; - let possiblePosition = new Position(lineNumber, column); - if (cursor.modelState.selectionStart.containsPosition(possiblePosition)) { - column = cursor.modelState.selectionStart.startColumn; - } - } - } - - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Explicit; - cursor.moveModelPosition(cursor.hasSelection(), lineNumber, column, 0, false); - return true; + public static word(cursor: OneCursor, inSelectionMode: boolean, validatedPosition: Position, ctx: IOneCursorOperationContext): boolean { + return this._applyMoveOperationResult( + cursor, ctx, + this._fromModelCursorState(cursor, WordOperations.word(cursor.config, cursor.model, cursor.modelState, inSelectionMode, validatedPosition)) + ); } public static cancelSelection(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - if (!cursor.hasSelection()) { + if (!cursor.modelState.hasSelection()) { return false; } @@ -1362,1038 +941,10 @@ export class OneCursorOp { } // -------------------- STOP handlers that simply change cursor state - - - - // -------------------- START type interceptors & co. - - private static _typeInterceptorEnter(cursor: OneCursor, ch: string, ctx: IOneCursorOperationContext): boolean { - if (ch !== '\n') { - return false; - } - - return this._enter(cursor, false, ctx, cursor.modelState.position, cursor.modelState.selection); - } - - public static lineInsertBefore(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - let lineNumber = cursor.modelState.position.lineNumber; - - if (lineNumber === 1) { - ctx.executeCommand = new ReplaceCommandWithoutChangingPosition(new Range(1, 1, 1, 1), '\n'); - return true; - } - - lineNumber--; - let column = cursor.model.getLineMaxColumn(lineNumber); - - return this._enter(cursor, false, ctx, new Position(lineNumber, column), new Range(lineNumber, column, lineNumber, column)); - } - - public static lineInsertAfter(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - let position = cursor.modelState.position; - let column = cursor.model.getLineMaxColumn(position.lineNumber); - return this._enter(cursor, false, ctx, new Position(position.lineNumber, column), new Range(position.lineNumber, column, position.lineNumber, column)); - } - - public static lineBreakInsert(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - return this._enter(cursor, true, ctx, cursor.modelState.position, cursor.modelState.selection); - } - - private static _enter(cursor: OneCursor, keepPosition: boolean, ctx: IOneCursorOperationContext, position: Position, range: Range): boolean { - ctx.shouldPushStackElementBefore = true; - - let r = LanguageConfigurationRegistry.getEnterActionAtPosition(cursor.model, range.startLineNumber, range.startColumn); - let enterAction = r.enterAction; - let indentation = r.indentation; - - ctx.isAutoWhitespaceCommand = true; - if (enterAction.indentAction === IndentAction.None) { - // Nothing special - this.actualType(cursor, '\n' + cursor.model.normalizeIndentation(indentation + enterAction.appendText), keepPosition, ctx, range); - - } else if (enterAction.indentAction === IndentAction.Indent) { - // Indent once - this.actualType(cursor, '\n' + cursor.model.normalizeIndentation(indentation + enterAction.appendText), keepPosition, ctx, range); - - } else if (enterAction.indentAction === IndentAction.IndentOutdent) { - // Ultra special - let normalIndent = cursor.model.normalizeIndentation(indentation); - let increasedIndent = cursor.model.normalizeIndentation(indentation + enterAction.appendText); - - let typeText = '\n' + increasedIndent + '\n' + normalIndent; - - if (keepPosition) { - ctx.executeCommand = new ReplaceCommandWithoutChangingPosition(range, typeText); - } else { - ctx.executeCommand = new ReplaceCommandWithOffsetCursorState(range, typeText, -1, increasedIndent.length - normalIndent.length); - } - } else if (enterAction.indentAction === IndentAction.Outdent) { - let desiredIndentCount = ShiftCommand.unshiftIndentCount(indentation, indentation.length + 1, cursor.model.getOptions().tabSize); - let actualIndentation = ''; - for (let i = 0; i < desiredIndentCount; i++) { - actualIndentation += '\t'; - } - this.actualType(cursor, '\n' + cursor.model.normalizeIndentation(actualIndentation + enterAction.appendText), keepPosition, ctx, range); - } - - return true; - } - - private static _typeInterceptorAutoClosingCloseChar(cursor: OneCursor, ch: string, ctx: IOneCursorOperationContext): boolean { - if (!cursor.configuration.editor.autoClosingBrackets) { - return false; - } - - let selection = cursor.modelState.selection; - - if (!selection.isEmpty() || !cursor.modeConfiguration.autoClosingPairsClose.hasOwnProperty(ch)) { - return false; - } - - let position = cursor.modelState.position; - - let lineText = cursor.model.getLineContent(position.lineNumber); - let beforeCharacter = lineText[position.column - 1]; - - if (beforeCharacter !== ch) { - return false; - } - - let typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1); - ctx.executeCommand = new ReplaceCommand(typeSelection, ch); - return true; - } - - private static _typeInterceptorAutoClosingOpenChar(cursor: OneCursor, ch: string, ctx: IOneCursorOperationContext): boolean { - if (!cursor.configuration.editor.autoClosingBrackets) { - return false; - } - - let selection = cursor.modelState.selection; - - if (!selection.isEmpty() || !cursor.modeConfiguration.autoClosingPairsOpen.hasOwnProperty(ch)) { - return false; - } - - let position = cursor.modelState.position; - let lineText = cursor.model.getLineContent(position.lineNumber); - let beforeCharacter = lineText[position.column - 1]; - - // Only consider auto closing the pair if a space follows or if another autoclosed pair follows - if (beforeCharacter) { - let isBeforeCloseBrace = false; - for (let closeBrace in cursor.modeConfiguration.autoClosingPairsClose) { - if (beforeCharacter === closeBrace) { - isBeforeCloseBrace = true; - break; - } - } - if (!isBeforeCloseBrace && !/\s/.test(beforeCharacter)) { - return false; - } - } - - let lineTokens = cursor.model.getLineTokens(position.lineNumber, false); - - let shouldAutoClosePair = false; - try { - shouldAutoClosePair = LanguageConfigurationRegistry.shouldAutoClosePair(ch, lineTokens, position.column - 1); - } catch (e) { - onUnexpectedError(e); - } - - if (!shouldAutoClosePair) { - return false; - } - - ctx.shouldPushStackElementBefore = true; - let closeCharacter = cursor.modeConfiguration.autoClosingPairsOpen[ch]; - ctx.executeCommand = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length); - return true; - } - - private static _typeInterceptorSurroundSelection(cursor: OneCursor, ch: string, ctx: IOneCursorOperationContext): boolean { - if (!cursor.configuration.editor.autoClosingBrackets) { - return false; - } - - let selection = cursor.modelState.selection; - - if (selection.isEmpty() || !cursor.modeConfiguration.surroundingPairs.hasOwnProperty(ch)) { - return false; - } - - let selectionContainsOnlyWhitespace = true; - - for (let lineNumber = selection.startLineNumber; lineNumber <= selection.endLineNumber; lineNumber++) { - let lineText = cursor.model.getLineContent(lineNumber); - let startIndex = (lineNumber === selection.startLineNumber ? selection.startColumn - 1 : 0); - let endIndex = (lineNumber === selection.endLineNumber ? selection.endColumn - 1 : lineText.length); - for (let charIndex = startIndex; charIndex < endIndex; charIndex++) { - let charCode = lineText.charCodeAt(charIndex); - if (charCode !== CharCode.Tab && charCode !== CharCode.Space) { - selectionContainsOnlyWhitespace = false; - - // Break outer loop - lineNumber = selection.endLineNumber + 1; - - // Break inner loop - charIndex = endIndex; - } - } - } - - if (selectionContainsOnlyWhitespace) { - return false; - } - - let closeCharacter = cursor.modeConfiguration.surroundingPairs[ch]; - - ctx.shouldPushStackElementBefore = true; - ctx.shouldPushStackElementAfter = true; - ctx.executeCommand = new SurroundSelectionCommand(selection, ch, closeCharacter); - return true; - } - - private static _typeInterceptorElectricChar(cursor: OneCursor, ch: string, ctx: IOneCursorOperationContext): boolean { - if (!cursor.modeConfiguration.electricChars.hasOwnProperty(ch)) { - return false; - } - - ctx.postOperationRunnable = (postOperationCtx: IOneCursorOperationContext) => this._typeInterceptorElectricCharRunnable(cursor, postOperationCtx); - - return this.actualType(cursor, ch, false, ctx); - } - - private static _typeInterceptorElectricCharRunnable(cursor: OneCursor, ctx: IOneCursorOperationContext): void { - - let position = cursor.modelState.position; - let lineText = cursor.model.getLineContent(position.lineNumber); - let lineTokens = cursor.model.getLineTokens(position.lineNumber, false); - - let electricAction: IElectricAction; - try { - electricAction = LanguageConfigurationRegistry.onElectricCharacter(lineTokens, position.column - 2); - } catch (e) { - onUnexpectedError(e); - } - - if (electricAction) { - let matchOpenBracket = electricAction.matchOpenBracket; - let appendText = electricAction.appendText; - if (matchOpenBracket) { - let match = cursor.model.findMatchingBracketUp(matchOpenBracket, { - lineNumber: position.lineNumber, - column: position.column - matchOpenBracket.length - }); - if (match) { - let matchLineNumber = match.startLineNumber; - let matchLine = cursor.model.getLineContent(matchLineNumber); - let matchLineIndentation = strings.getLeadingWhitespace(matchLine); - let newIndentation = cursor.model.normalizeIndentation(matchLineIndentation); - - let lineFirstNonBlankColumn = cursor.model.getLineFirstNonWhitespaceColumn(position.lineNumber) || position.column; - let oldIndentation = lineText.substring(0, lineFirstNonBlankColumn - 1); - - if (oldIndentation !== newIndentation) { - let prefix = lineText.substring(lineFirstNonBlankColumn - 1, position.column - 1); - let typeText = newIndentation + prefix; - - let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column); - ctx.shouldPushStackElementAfter = true; - ctx.executeCommand = new ReplaceCommand(typeSelection, typeText); - } - } - } else if (appendText) { - let columnDeltaOffset = -appendText.length; - if (electricAction.advanceCount) { - columnDeltaOffset += electricAction.advanceCount; - } - ctx.shouldPushStackElementAfter = true; - ctx.executeCommand = new ReplaceCommandWithOffsetCursorState(cursor.modelState.selection, appendText, 0, columnDeltaOffset); - } - } - } - - public static actualType(cursor: OneCursor, text: string, keepPosition: boolean, ctx: IOneCursorOperationContext, range?: Range): boolean { - if (typeof range === 'undefined') { - range = cursor.modelState.selection; - } - if (keepPosition) { - ctx.executeCommand = new ReplaceCommandWithoutChangingPosition(range, text); - } else { - ctx.executeCommand = new ReplaceCommand(range, text); - } - return true; - } - - public static type(cursor: OneCursor, ch: string, ctx: IOneCursorOperationContext): boolean { - - if (this._typeInterceptorEnter(cursor, ch, ctx)) { - return true; - } - - if (this._typeInterceptorAutoClosingCloseChar(cursor, ch, ctx)) { - return true; - } - - if (this._typeInterceptorAutoClosingOpenChar(cursor, ch, ctx)) { - return true; - } - - if (this._typeInterceptorSurroundSelection(cursor, ch, ctx)) { - return true; - } - - if (this._typeInterceptorElectricChar(cursor, ch, ctx)) { - return true; - } - - return this.actualType(cursor, ch, false, ctx); - } - - public static replacePreviousChar(cursor: OneCursor, txt: string, replaceCharCnt: number, ctx: IOneCursorOperationContext): boolean { - let pos = cursor.modelState.position; - let range: Range; - let startColumn = Math.max(1, pos.column - replaceCharCnt); - range = new Range(pos.lineNumber, startColumn, pos.lineNumber, pos.column); - ctx.executeCommand = new ReplaceCommand(range, txt); - return true; - } - - private static _goodIndentForLine(cursor: OneCursor, lineNumber: number): string { - let lastLineNumber = lineNumber - 1; - - for (lastLineNumber = lineNumber - 1; lastLineNumber >= 1; lastLineNumber--) { - let lineText = cursor.model.getLineContent(lastLineNumber); - let nonWhitespaceIdx = strings.lastNonWhitespaceIndex(lineText); - if (nonWhitespaceIdx >= 0) { - break; - } - } - - if (lastLineNumber < 1) { - // No previous line with content found - return '\t'; - } - - let r = LanguageConfigurationRegistry.getEnterActionAtPosition(cursor.model, lastLineNumber, cursor.model.getLineMaxColumn(lastLineNumber)); - - let indentation: string; - if (r.enterAction.indentAction === IndentAction.Outdent) { - let modelOpts = cursor.model.getOptions(); - let desiredIndentCount = ShiftCommand.unshiftIndentCount(r.indentation, r.indentation.length, modelOpts.tabSize); - indentation = ''; - for (let i = 0; i < desiredIndentCount; i++) { - indentation += '\t'; - } - indentation = cursor.model.normalizeIndentation(indentation); - } else { - indentation = r.indentation; - } - - let result = indentation + r.enterAction.appendText; - if (result.length === 0) { - // good position is at column 1, but we gotta do something... - return '\t'; - } - return result; - } - - private static _replaceJumpToNextIndent(cursor: OneCursor, selection: Selection): ReplaceCommand { - let typeText = ''; - - let position = selection.getStartPosition(); - let modelOpts = cursor.model.getOptions(); - if (modelOpts.insertSpaces) { - let visibleColumnFromColumn = cursor.getVisibleColumnFromColumn(position.lineNumber, position.column); - let tabSize = modelOpts.tabSize; - let spacesCnt = tabSize - (visibleColumnFromColumn % tabSize); - for (let i = 0; i < spacesCnt; i++) { - typeText += ' '; - } - } else { - typeText = '\t'; - } - - return new ReplaceCommand(selection, typeText); - } - - public static tab(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - let selection = cursor.modelState.selection; - - if (selection.isEmpty()) { - - ctx.isAutoWhitespaceCommand = true; - - - let lineText = cursor.model.getLineContent(selection.startLineNumber); - - if (/^\s*$/.test(lineText)) { - let possibleTypeText = cursor.model.normalizeIndentation(this._goodIndentForLine(cursor, selection.startLineNumber)); - if (!strings.startsWith(lineText, possibleTypeText)) { - ctx.executeCommand = new ReplaceCommand(new Range(selection.startLineNumber, 1, selection.startLineNumber, lineText.length + 1), possibleTypeText); - return true; - } - } - - ctx.executeCommand = this._replaceJumpToNextIndent(cursor, selection); - return true; - } else { - if (selection.startLineNumber === selection.endLineNumber) { - let lineMaxColumn = cursor.model.getLineMaxColumn(selection.startLineNumber); - if (selection.startColumn !== 1 || selection.endColumn !== lineMaxColumn) { - // This is a single line selection that is not the entire line - ctx.executeCommand = this._replaceJumpToNextIndent(cursor, selection); - return true; - } - } - return this.indent(cursor, ctx); - } - } - - public static indent(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - let selection = cursor.modelState.selection; - - ctx.shouldPushStackElementBefore = true; - ctx.shouldPushStackElementAfter = true; - ctx.executeCommand = new ShiftCommand(selection, { - isUnshift: false, - tabSize: cursor.model.getOptions().tabSize, - oneIndent: cursor.model.getOneIndent() - }); - ctx.shouldRevealHorizontal = false; - - return true; - } - - public static outdent(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - let selection = cursor.modelState.selection; - - ctx.shouldPushStackElementBefore = true; - ctx.shouldPushStackElementAfter = true; - ctx.executeCommand = new ShiftCommand(selection, { - isUnshift: true, - tabSize: cursor.model.getOptions().tabSize, - oneIndent: cursor.model.getOneIndent() - }); - ctx.shouldRevealHorizontal = false; - - return true; - } - - public static paste(cursor: OneCursor, text: string, pasteOnNewLine: boolean, ctx: IOneCursorOperationContext): boolean { - let position = cursor.modelState.position; - let selection = cursor.modelState.selection; - - ctx.cursorPositionChangeReason = editorCommon.CursorChangeReason.Paste; - - if (pasteOnNewLine && text.indexOf('\n') !== text.length - 1) { - pasteOnNewLine = false; - } - if (pasteOnNewLine && selection.startLineNumber !== selection.endLineNumber) { - pasteOnNewLine = false; - } - if (pasteOnNewLine && selection.startColumn === cursor.model.getLineMinColumn(selection.startLineNumber) && selection.endColumn === cursor.model.getLineMaxColumn(selection.startLineNumber)) { - pasteOnNewLine = false; - } - - if (pasteOnNewLine) { - // Paste entire line at the beginning of line - - let typeSelection = new Range(position.lineNumber, 1, position.lineNumber, 1); - ctx.executeCommand = new ReplaceCommand(typeSelection, text); - return true; - } - ctx.executeCommand = new ReplaceCommand(selection, text); - return true; - } - - // -------------------- END type interceptors & co. - - // -------------------- START delete handlers & co. - - private static _autoClosingPairDelete(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - // Returns true if delete was handled. - - if (!cursor.configuration.editor.autoClosingBrackets) { - return false; - } - - if (!cursor.modelState.selection.isEmpty()) { - return false; - } - - let position = cursor.modelState.position; - - let lineText = cursor.model.getLineContent(position.lineNumber); - let character = lineText[position.column - 2]; - - if (!cursor.modeConfiguration.autoClosingPairsOpen.hasOwnProperty(character)) { - return false; - } - - let afterCharacter = lineText[position.column - 1]; - let closeCharacter = cursor.modeConfiguration.autoClosingPairsOpen[character]; - - if (afterCharacter !== closeCharacter) { - return false; - } - - let deleteSelection = new Range( - position.lineNumber, - position.column - 1, - position.lineNumber, - position.column + 1 - ); - ctx.executeCommand = new ReplaceCommand(deleteSelection, ''); - - return true; - } - - public static deleteLeft(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - if (this._autoClosingPairDelete(cursor, ctx)) { - // This was a case for an auto-closing pair delete - return true; - } - - let deleteSelection: Range = cursor.modelState.selection; - - if (deleteSelection.isEmpty()) { - let position = cursor.modelState.position; - - if (cursor.configuration.editor.useTabStops && position.column > 1) { - let lineContent = cursor.model.getLineContent(position.lineNumber); - - let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent); - let lastIndentationColumn = ( - firstNonWhitespaceIndex === -1 - ? /* entire string is whitespace */lineContent.length + 1 - : firstNonWhitespaceIndex + 1 - ); - - if (position.column <= lastIndentationColumn) { - let fromVisibleColumn = cursor.getVisibleColumnFromColumn(position.lineNumber, position.column); - let toVisibleColumn = CursorMoveHelper.prevTabColumn(fromVisibleColumn, cursor.model.getOptions().tabSize); - let toColumn = CursorMove.columnFromVisibleColumn(cursor.config, cursor.model, position.lineNumber, toVisibleColumn); - deleteSelection = new Range(position.lineNumber, toColumn, position.lineNumber, position.column); - } else { - deleteSelection = new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column); - } - } else { - let leftOfPosition = CursorMove.left(cursor.config, cursor.model, position.lineNumber, position.column); - deleteSelection = new Range( - leftOfPosition.lineNumber, - leftOfPosition.column, - position.lineNumber, - position.column - ); - } - } - - if (deleteSelection.isEmpty()) { - // Probably at beginning of file => ignore - return true; - } - - if (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) { - ctx.shouldPushStackElementBefore = true; - } - - ctx.executeCommand = new ReplaceCommand(deleteSelection, ''); - return true; - } - - private static deleteWordLeftWhitespace(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - let position = cursor.modelState.position; - let lineContent = cursor.model.getLineContent(position.lineNumber); - let startIndex = position.column - 2; - let lastNonWhitespace = strings.lastNonWhitespaceIndex(lineContent, startIndex); - if (lastNonWhitespace + 1 < startIndex) { - // bingo - ctx.executeCommand = new ReplaceCommand(new Range(position.lineNumber, lastNonWhitespace + 2, position.lineNumber, position.column), ''); - return true; - } - return false; - } - - public static deleteWordLeft(cursor: OneCursor, whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType, ctx: IOneCursorOperationContext): boolean { - if (this._autoClosingPairDelete(cursor, ctx)) { - // This was a case for an auto-closing pair delete - return true; - } - - let selection = cursor.modelState.selection; - - if (selection.isEmpty()) { - let position = cursor.modelState.position; - - let lineNumber = position.lineNumber; - let column = position.column; - - if (lineNumber === 1 && column === 1) { - // Ignore deleting at beginning of file - return true; - } - - if (whitespaceHeuristics && this.deleteWordLeftWhitespace(cursor, ctx)) { - return true; - } - - let prevWordOnLine = cursor.findPreviousWordOnLine(position); - - if (wordNavigationType === WordNavigationType.WordStart) { - if (prevWordOnLine) { - column = prevWordOnLine.start + 1; - } else { - column = 1; - } - } else { - if (prevWordOnLine && column <= prevWordOnLine.end + 1) { - prevWordOnLine = cursor.findPreviousWordOnLine(new Position(lineNumber, prevWordOnLine.start + 1)); - } - if (prevWordOnLine) { - column = prevWordOnLine.end + 1; - } else { - column = 1; - } - } - - let deleteSelection = new Range(lineNumber, column, lineNumber, position.column); - if (!deleteSelection.isEmpty()) { - ctx.executeCommand = new ReplaceCommand(deleteSelection, ''); - return true; - } - } - - return this.deleteLeft(cursor, ctx); - } - - public static deleteRight(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - - let deleteSelection: Range = cursor.modelState.selection; - - if (deleteSelection.isEmpty()) { - let position = cursor.modelState.position; - let rightOfPosition = CursorMove.right(cursor.config, cursor.model, position.lineNumber, position.column); - deleteSelection = new Range( - rightOfPosition.lineNumber, - rightOfPosition.column, - position.lineNumber, - position.column - ); - } - - if (deleteSelection.isEmpty()) { - // Probably at end of file => ignore - return true; - } - - if (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) { - ctx.shouldPushStackElementBefore = true; - } - - ctx.executeCommand = new ReplaceCommand(deleteSelection, ''); - return true; - } - - private static _findFirstNonWhitespaceChar(str: string, startIndex: number): number { - let len = str.length; - for (let chIndex = startIndex; chIndex < len; chIndex++) { - let ch = str.charAt(chIndex); - if (ch !== ' ' && ch !== '\t') { - return chIndex; - } - } - return len; - } - - private static deleteWordRightWhitespace(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - let position = cursor.modelState.position; - let lineContent = cursor.model.getLineContent(position.lineNumber); - let startIndex = position.column - 1; - let firstNonWhitespace = this._findFirstNonWhitespaceChar(lineContent, startIndex); - if (startIndex + 1 < firstNonWhitespace) { - // bingo - ctx.executeCommand = new ReplaceCommand(new Range(position.lineNumber, position.column, position.lineNumber, firstNonWhitespace + 1), ''); - return true; - } - return false; - } - - public static deleteWordRight(cursor: OneCursor, whitespaceHeuristics: boolean, wordNavigationType: WordNavigationType, ctx: IOneCursorOperationContext): boolean { - - let selection = cursor.modelState.selection; - - if (selection.isEmpty()) { - let position = cursor.modelState.position; - - let lineNumber = position.lineNumber; - let column = position.column; - - let lineCount = cursor.model.getLineCount(); - let maxColumn = cursor.model.getLineMaxColumn(lineNumber); - if (lineNumber === lineCount && column === maxColumn) { - // Ignore deleting at end of file - return true; - } - - if (whitespaceHeuristics && this.deleteWordRightWhitespace(cursor, ctx)) { - return true; - } - - let nextWordOnLine = cursor.findNextWordOnLine(position); - - if (wordNavigationType === WordNavigationType.WordEnd) { - if (nextWordOnLine) { - column = nextWordOnLine.end + 1; - } else { - if (column < maxColumn || lineNumber === lineCount) { - column = maxColumn; - } else { - lineNumber++; - nextWordOnLine = cursor.findNextWordOnLine(new Position(lineNumber, 1)); - if (nextWordOnLine) { - column = nextWordOnLine.start + 1; - } else { - column = cursor.model.getLineMaxColumn(lineNumber); - } - } - } - } else { - if (nextWordOnLine && column >= nextWordOnLine.start + 1) { - nextWordOnLine = cursor.findNextWordOnLine(new Position(lineNumber, nextWordOnLine.end + 1)); - } - if (nextWordOnLine) { - column = nextWordOnLine.start + 1; - } else { - if (column < maxColumn || lineNumber === lineCount) { - column = maxColumn; - } else { - lineNumber++; - nextWordOnLine = cursor.findNextWordOnLine(new Position(lineNumber, 1)); - if (nextWordOnLine) { - column = nextWordOnLine.start + 1; - } else { - column = cursor.model.getLineMaxColumn(lineNumber); - } - } - } - } - - let deleteSelection = new Range(lineNumber, column, position.lineNumber, position.column); - if (!deleteSelection.isEmpty()) { - ctx.executeCommand = new ReplaceCommand(deleteSelection, ''); - return true; - } - } - // fall back to normal deleteRight behavior - return this.deleteRight(cursor, ctx); - } - - public static deleteAllLeft(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - if (this._autoClosingPairDelete(cursor, ctx)) { - // This was a case for an auto-closing pair delete - return true; - } - - let selection = cursor.modelState.selection; - - if (selection.isEmpty()) { - let position = cursor.modelState.position; - let lineNumber = position.lineNumber; - let column = position.column; - - if (column === 1) { - // Ignore deleting at beginning of line - return true; - } - - let deleteSelection = new Range(lineNumber, 1, lineNumber, column); - if (!deleteSelection.isEmpty()) { - ctx.executeCommand = new ReplaceCommand(deleteSelection, ''); - return true; - } - } - - return this.deleteLeft(cursor, ctx); - } - - public static deleteAllRight(cursor: OneCursor, ctx: IOneCursorOperationContext): boolean { - let selection = cursor.modelState.selection; - - if (selection.isEmpty()) { - let position = cursor.modelState.position; - let lineNumber = position.lineNumber; - let column = position.column; - let maxColumn = cursor.model.getLineMaxColumn(lineNumber); - - if (column === maxColumn) { - // Ignore deleting at end of file - return true; - } - - let deleteSelection = new Range(lineNumber, column, lineNumber, maxColumn); - if (!deleteSelection.isEmpty()) { - ctx.executeCommand = new ReplaceCommand(deleteSelection, ''); - return true; - } - } - - return this.deleteRight(cursor, ctx); - } - - public static cut(cursor: OneCursor, enableEmptySelectionClipboard: boolean, ctx: IOneCursorOperationContext): boolean { - let selection = cursor.modelState.selection; - - if (selection.isEmpty()) { - if (enableEmptySelectionClipboard) { - // This is a full line cut - - let position = cursor.modelState.position; - - let startLineNumber: number, - startColumn: number, - endLineNumber: number, - endColumn: number; - - if (position.lineNumber < cursor.model.getLineCount()) { - // Cutting a line in the middle of the model - startLineNumber = position.lineNumber; - startColumn = 1; - endLineNumber = position.lineNumber + 1; - endColumn = 1; - } else if (position.lineNumber > 1) { - // Cutting the last line & there are more than 1 lines in the model - startLineNumber = position.lineNumber - 1; - startColumn = cursor.model.getLineMaxColumn(position.lineNumber - 1); - endLineNumber = position.lineNumber; - endColumn = cursor.model.getLineMaxColumn(position.lineNumber); - } else { - // Cutting the single line that the model contains - startLineNumber = position.lineNumber; - startColumn = 1; - endLineNumber = position.lineNumber; - endColumn = cursor.model.getLineMaxColumn(position.lineNumber); - } - - let deleteSelection = new Range( - startLineNumber, - startColumn, - endLineNumber, - endColumn - ); - - if (!deleteSelection.isEmpty()) { - ctx.executeCommand = new ReplaceCommand(deleteSelection, ''); - } - } else { - // Cannot cut empty selection - return false; - } - } else { - // Delete left or right, they will both result in the selection being deleted - this.deleteRight(cursor, ctx); - } - return true; - } - - // -------------------- END delete handlers & co. } -class CursorHelper { - private model: editorCommon.IModel; - private configuration: editorCommon.IConfiguration; - private moveHelper: CursorMoveHelper; - - constructor(model: editorCommon.IModel, configuration: editorCommon.IConfiguration, config: CursorMoveConfiguration) { - this.model = model; - this.configuration = configuration; - this.moveHelper = new CursorMoveHelper(config); - } - - public getColumnAtBeginningOfLine(model: ICursorMoveHelperModel, lineNumber: number, column: number): number { - return this.moveHelper.getColumnAtBeginningOfLine(model, lineNumber, column); - } - - public getColumnAtEndOfLine(model: ICursorMoveHelperModel, lineNumber: number, column: number): number { - return this.moveHelper.getColumnAtEndOfLine(model, lineNumber, column); - } - - public columnSelect(model: ICursorMoveHelperModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IViewColumnSelectResult { - return this.moveHelper.columnSelect(model, fromLineNumber, fromVisibleColumn, toLineNumber, toVisibleColumn); - } - - public visibleColumnFromColumn(model: ICursorMoveHelperModel, lineNumber: number, column: number): number { - return this.moveHelper.visibleColumnFromColumn(model, lineNumber, column); - } - - private static _createWord(lineContent: string, wordType: WordType, start: number, end: number): IFindWordResult { - // console.log('WORD ==> ' + start + ' => ' + end + ':::: <<<' + lineContent.substring(start, end) + '>>>'); - return { start: start, end: end, wordType: wordType }; - } - - public findPreviousWordOnLine(_position: Position): IFindWordResult { - let position = this.model.validatePosition(_position); - let wordSeparators = getMapForWordSeparators(this.configuration.editor.wordSeparators); - let lineContent = this.model.getLineContent(position.lineNumber); - return CursorHelper._findPreviousWordOnLine(lineContent, wordSeparators, position); - } - - private static _findPreviousWordOnLine(lineContent: string, wordSeparators: WordCharacterClassifier, position: Position): IFindWordResult { - let wordType = WordType.None; - for (let chIndex = position.column - 2; chIndex >= 0; chIndex--) { - let chCode = lineContent.charCodeAt(chIndex); - let chClass = wordSeparators.get(chCode); - - if (chClass === CharacterClass.Regular) { - if (wordType === WordType.Separator) { - return CursorHelper._createWord(lineContent, wordType, chIndex + 1, CursorHelper._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); - } - wordType = WordType.Regular; - } else if (chClass === CharacterClass.WordSeparator) { - if (wordType === WordType.Regular) { - return CursorHelper._createWord(lineContent, wordType, chIndex + 1, CursorHelper._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); - } - wordType = WordType.Separator; - } else if (chClass === CharacterClass.Whitespace) { - if (wordType !== WordType.None) { - return CursorHelper._createWord(lineContent, wordType, chIndex + 1, CursorHelper._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1)); - } - } - } - - if (wordType !== WordType.None) { - return CursorHelper._createWord(lineContent, wordType, 0, CursorHelper._findEndOfWord(lineContent, wordSeparators, wordType, 0)); - } - - return null; - } - - private static _findEndOfWord(lineContent: string, wordSeparators: WordCharacterClassifier, wordType: WordType, startIndex: number): number { - let len = lineContent.length; - for (let chIndex = startIndex; chIndex < len; chIndex++) { - let chCode = lineContent.charCodeAt(chIndex); - let chClass = wordSeparators.get(chCode); - - if (chClass === CharacterClass.Whitespace) { - return chIndex; - } - if (wordType === WordType.Regular && chClass === CharacterClass.WordSeparator) { - return chIndex; - } - if (wordType === WordType.Separator && chClass === CharacterClass.Regular) { - return chIndex; - } - } - return len; - } - - public findNextWordOnLine(_position: Position): IFindWordResult { - let position = this.model.validatePosition(_position); - let wordSeparators = getMapForWordSeparators(this.configuration.editor.wordSeparators); - let lineContent = this.model.getLineContent(position.lineNumber); - return CursorHelper._findNextWordOnLine(lineContent, wordSeparators, position); - } - - private static _findNextWordOnLine(lineContent: string, wordSeparators: WordCharacterClassifier, position: Position): IFindWordResult { - let wordType = WordType.None; - let len = lineContent.length; - - for (let chIndex = position.column - 1; chIndex < len; chIndex++) { - let chCode = lineContent.charCodeAt(chIndex); - let chClass = wordSeparators.get(chCode); - - if (chClass === CharacterClass.Regular) { - if (wordType === WordType.Separator) { - return CursorHelper._createWord(lineContent, wordType, CursorHelper._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); - } - wordType = WordType.Regular; - } else if (chClass === CharacterClass.WordSeparator) { - if (wordType === WordType.Regular) { - return CursorHelper._createWord(lineContent, wordType, CursorHelper._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); - } - wordType = WordType.Separator; - } else if (chClass === CharacterClass.Whitespace) { - if (wordType !== WordType.None) { - return CursorHelper._createWord(lineContent, wordType, CursorHelper._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex); - } - } - } - - if (wordType !== WordType.None) { - return CursorHelper._createWord(lineContent, wordType, CursorHelper._findStartOfWord(lineContent, wordSeparators, wordType, len - 1), len); - } - - return null; - } - - private static _findStartOfWord(lineContent: string, wordSeparators: WordCharacterClassifier, wordType: WordType, startIndex: number): number { - for (let chIndex = startIndex; chIndex >= 0; chIndex--) { - let chCode = lineContent.charCodeAt(chIndex); - let chClass = wordSeparators.get(chCode); - - if (chClass === CharacterClass.Whitespace) { - return chIndex + 1; - } - if (wordType === WordType.Regular && chClass === CharacterClass.WordSeparator) { - return chIndex + 1; - } - if (wordType === WordType.Separator && chClass === CharacterClass.Regular) { - return chIndex + 1; - } - } - return 0; - } -} - -class WordCharacterClassifier extends CharacterClassifier { - - constructor(wordSeparators: string) { - super(CharacterClass.Regular); - - for (let i = 0, len = wordSeparators.length; i < len; i++) { - this.set(wordSeparators.charCodeAt(i), CharacterClass.WordSeparator); - } - - this.set(CharCode.Space, CharacterClass.Whitespace); - this.set(CharCode.Tab, CharacterClass.Whitespace); - } - -} - -function once(computeFn: (input: string) => R): (input: string) => R { - let cache: { [key: string]: R; } = {}; // TODO@Alex unbounded cache - return (input: string): R => { - if (!cache.hasOwnProperty(input)) { - cache[input] = computeFn(input); - } - return cache[input]; - }; -} - -let getMapForWordSeparators = once( - (input) => new WordCharacterClassifier(input) -); - class Utils { - /** - * Range contains position (including edges)? - */ - static rangeContainsPosition(range: editorCommon.IRange, position: editorCommon.IPosition): boolean { - if (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) { - return false; - } - if (position.lineNumber === range.startLineNumber && position.column < range.startColumn) { - return false; - } - if (position.lineNumber === range.endLineNumber && position.column > range.endColumn) { - return false; - } - return true; - } - /** * Tests if position is contained inside range. * If position is either the starting or ending of a range, false is returned. diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 604a6faf69e..8475280eb74 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -125,10 +125,7 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo }); } - private _normalizeIndentationFromWhitespace(str: string): string { - let tabSize = this._options.tabSize; - let insertSpaces = this._options.insertSpaces; - + private static _normalizeIndentationFromWhitespace(str: string, tabSize: number, insertSpaces: boolean): string { let spacesCnt = 0; for (let i = 0; i < str.length; i++) { if (str.charAt(i) === '\t') { @@ -154,13 +151,17 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo return result; } - public normalizeIndentation(str: string): string { - this._assertNotDisposed(); + public static normalizeIndentation(str: string, tabSize: number, insertSpaces: boolean): string { let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(str); if (firstNonWhitespaceIndex === -1) { firstNonWhitespaceIndex = str.length; } - return this._normalizeIndentationFromWhitespace(str.substring(0, firstNonWhitespaceIndex)) + str.substring(firstNonWhitespaceIndex); + return TextModel._normalizeIndentationFromWhitespace(str.substring(0, firstNonWhitespaceIndex), tabSize, insertSpaces) + str.substring(firstNonWhitespaceIndex); + } + + public normalizeIndentation(str: string): string { + this._assertNotDisposed(); + return TextModel.normalizeIndentation(str, this._options.tabSize, this._options.insertSpaces); } public getOneIndent(): string { @@ -830,7 +831,7 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo throw new Error('Unknown EOL preference'); } - private static _isMultiline(searchString: string): boolean { + private static _isMultilineRegexSource(searchString: string): boolean { if (!searchString || searchString.length === 0) { return false; } @@ -864,8 +865,14 @@ export class TextModel extends OrderGuaranteeEventEmitter implements editorCommo } // Try to create a RegExp out of the params - var regex: RegExp = null; - var multiline = isRegex && TextModel._isMultiline(searchString); + let multiline: boolean; + if (isRegex) { + multiline = TextModel._isMultilineRegexSource(searchString); + } else { + multiline = (searchString.indexOf('\n') >= 0); + } + + let regex: RegExp = null; try { regex = strings.createRegExp(searchString, isRegex, { matchCase, wholeWord, multiline, global: true }); } catch (err) { diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 13e4a00d227..14ba3a2df64 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -186,6 +186,7 @@ export interface ISuggestion { additionalTextEdits?: editorCommon.ISingleEditOperation[]; command?: Command; isTMSnippet?: boolean; + _extensionId?: string; } /** diff --git a/src/vs/editor/common/modes/languageConfigurationRegistry.ts b/src/vs/editor/common/modes/languageConfigurationRegistry.ts index 37c78d0f801..4d6d1ac0f04 100644 --- a/src/vs/editor/common/modes/languageConfigurationRegistry.ts +++ b/src/vs/editor/common/modes/languageConfigurationRegistry.ts @@ -162,13 +162,13 @@ export class LanguageConfigurationRegistryImpl { /** * Should return opening bracket type to match indentation with */ - public onElectricCharacter(context: LineTokens, offset: number): IElectricAction { - let scopedLineTokens = createScopedLineTokens(context, offset); + public onElectricCharacter(character: string, context: LineTokens, column: number): IElectricAction { + let scopedLineTokens = createScopedLineTokens(context, column - 1); let electricCharacterSupport = this._getElectricCharacterSupport(scopedLineTokens.modeId); if (!electricCharacterSupport) { return null; } - return electricCharacterSupport.onElectricCharacter(scopedLineTokens, offset - scopedLineTokens.firstCharOffset); + return electricCharacterSupport.onElectricCharacter(character, scopedLineTokens, column - scopedLineTokens.firstCharOffset); } // end electricCharacter @@ -207,13 +207,13 @@ export class LanguageConfigurationRegistryImpl { return characterPairSupport.getSurroundingPairs(); } - public shouldAutoClosePair(character: string, context: LineTokens, offset: number): boolean { - let scopedLineTokens = createScopedLineTokens(context, offset); + public shouldAutoClosePair(character: string, context: LineTokens, column: number): boolean { + let scopedLineTokens = createScopedLineTokens(context, column - 1); let characterPairSupport = this._getCharacterPairSupport(scopedLineTokens.modeId); if (!characterPairSupport) { return false; } - return characterPairSupport.shouldAutoClosePair(character, scopedLineTokens, offset - scopedLineTokens.firstCharOffset); + return characterPairSupport.shouldAutoClosePair(character, scopedLineTokens, column - scopedLineTokens.firstCharOffset); } // end characterPair diff --git a/src/vs/editor/common/modes/modesRegistry.ts b/src/vs/editor/common/modes/modesRegistry.ts index 94b4432a588..f6fe33c690b 100644 --- a/src/vs/editor/common/modes/modesRegistry.ts +++ b/src/vs/editor/common/modes/modesRegistry.ts @@ -8,7 +8,7 @@ import * as nls from 'vs/nls'; import Event, { Emitter } from 'vs/base/common/event'; import { Registry } from 'vs/platform/platform'; import { ILanguageExtensionPoint } from 'vs/editor/common/services/modeService'; - +import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; // Define extension point ids export var Extensions = { ModesRegistry: 'editor.modesRegistry' @@ -51,3 +51,10 @@ ModesRegistry.registerLanguage({ aliases: [nls.localize('plainText.alias', "Plain Text"), 'text'], mimetypes: ['text/plain'] }); +LanguageConfigurationRegistry.register(PLAINTEXT_MODE_ID, { + brackets: [ + ['(', ')'], + ['[', ']'], + ['{', '}'], + ] +}); diff --git a/src/vs/editor/common/modes/supports/characterPair.ts b/src/vs/editor/common/modes/supports/characterPair.ts index d4f72526ae8..6e87fffcee2 100644 --- a/src/vs/editor/common/modes/supports/characterPair.ts +++ b/src/vs/editor/common/modes/supports/characterPair.ts @@ -28,13 +28,13 @@ export class CharacterPairSupport { return this._autoClosingPairs; } - public shouldAutoClosePair(character: string, context: ScopedLineTokens, offset: number): boolean { + public shouldAutoClosePair(character: string, context: ScopedLineTokens, column: number): boolean { // Always complete on empty line if (context.getTokenCount() === 0) { return true; } - let tokenIndex = context.findTokenIndexAtOffset(offset - 1); + let tokenIndex = context.findTokenIndexAtOffset(column - 2); let standardTokenType = context.getStandardTokenType(tokenIndex); for (let i = 0; i < this._autoClosingPairs.length; ++i) { diff --git a/src/vs/editor/common/modes/supports/electricCharacter.ts b/src/vs/editor/common/modes/supports/electricCharacter.ts index 7e13ce5a656..94f242b51d3 100644 --- a/src/vs/editor/common/modes/supports/electricCharacter.ts +++ b/src/vs/editor/common/modes/supports/electricCharacter.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as strings from 'vs/base/common/strings'; import { ScopedLineTokens, ignoreBracketsInToken } from 'vs/editor/common/modes/supports'; import { BracketsUtils } from 'vs/editor/common/modes/supports/richEditBrackets'; import { RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets'; @@ -23,9 +22,6 @@ export interface IElectricAction { // The text will be appended after the electric character. appendText?: string; - - // The number of characters to advance the cursor, useful with appendText - advanceCount?: number; } export class BracketElectricCharacterSupport { @@ -67,86 +63,79 @@ export class BracketElectricCharacterSupport { return result; } - public onElectricCharacter(context: ScopedLineTokens, offset: number): IElectricAction { - if (context.getTokenCount() === 0) { - return null; - } - - return (this._onElectricAutoClose(context, offset) || - this._onElectricAutoIndent(context, offset)); + public onElectricCharacter(character: string, context: ScopedLineTokens, column: number): IElectricAction { + return (this._onElectricAutoClose(character, context, column) || + this._onElectricAutoIndent(character, context, column)); } - private _onElectricAutoIndent(context: ScopedLineTokens, offset: number): IElectricAction { + private _onElectricAutoIndent(character: string, context: ScopedLineTokens, column: number): IElectricAction { if (!this._richEditBrackets || this._richEditBrackets.brackets.length === 0) { return null; } - let reversedBracketRegex = this._richEditBrackets.reversedRegex; - - let lineText = context.getLineContent(); - let tokenIndex = context.findTokenIndexAtOffset(offset); - let tokenStart = context.getTokenStartOffset(tokenIndex); - let tokenEnd = offset + 1; - - var firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(context.getLineContent()); - if (firstNonWhitespaceIndex !== -1 && firstNonWhitespaceIndex < tokenStart) { + let tokenIndex = context.findTokenIndexAtOffset(column - 1); + if (ignoreBracketsInToken(context.getStandardTokenType(tokenIndex))) { return null; } - if (!ignoreBracketsInToken(context.getStandardTokenType(tokenIndex))) { - let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, 1, lineText, tokenStart, tokenEnd); - if (r) { - let text = lineText.substring(r.startColumn - 1, r.endColumn - 1); - text = text.toLowerCase(); + let reversedBracketRegex = this._richEditBrackets.reversedRegex; + let text = context.getLineContent().substring(0, column - 1) + character; - let isOpen = this._richEditBrackets.textIsOpenBracket[text]; - if (!isOpen) { - return { - matchOpenBracket: text - }; - } - } + let r = BracketsUtils.findPrevBracketInToken(reversedBracketRegex, 1, text, 0, text.length); + if (!r) { + return null; } - return null; + let bracketText = text.substring(r.startColumn - 1, r.endColumn - 1); + bracketText = bracketText.toLowerCase(); + + let isOpen = this._richEditBrackets.textIsOpenBracket[bracketText]; + if (isOpen) { + return null; + } + + return { + matchOpenBracket: bracketText + }; } - private _onElectricAutoClose(context: ScopedLineTokens, offset: number): IElectricAction { - + private _onElectricAutoClose(character: string, context: ScopedLineTokens, column: number): IElectricAction { if (!this._complexAutoClosePairs.length) { return null; } - var line = context.getLineContent(); - var char: string = line[offset]; + let line = context.getLineContent(); - for (let i = 0; i < this._complexAutoClosePairs.length; i++) { + for (let i = 0, len = this._complexAutoClosePairs.length; i < len; i++) { let pair = this._complexAutoClosePairs[i]; // See if the right electric character was pressed - if (char !== pair.open.charAt(pair.open.length - 1)) { - continue; - } - - // If this line already contains the closing tag, do nothing. - if (line.indexOf(pair.close, offset) >= 0) { + if (character !== pair.open.charAt(pair.open.length - 1)) { continue; } // check if the full open bracket matches - let lastTokenIndex = context.findTokenIndexAtOffset(offset); - if (line.substring(context.getTokenStartOffset(lastTokenIndex), offset + 1/* include electric char*/) !== pair.open) { + let actual = line.substring(line.length - pair.open.length + 1) + character; + if (actual !== pair.open) { continue; } + let lastTokenIndex = context.findTokenIndexAtOffset(column - 1); + let lastTokenStandardType = context.getStandardTokenType(lastTokenIndex); // If we're in a scope listed in 'notIn', do nothing - if (!pair.isOK(context.getStandardTokenType(lastTokenIndex))) { + if (!pair.isOK(lastTokenStandardType)) { + continue; + } + + // If this line already contains the closing tag, do nothing. + if (line.indexOf(pair.close, column - 1) >= 0) { continue; } return { appendText: pair.close }; } + return null; } } diff --git a/src/vs/editor/common/services/bulkEdit.ts b/src/vs/editor/common/services/bulkEdit.ts index e2e08216d8c..bb19d42bfcd 100644 --- a/src/vs/editor/common/services/bulkEdit.ts +++ b/src/vs/editor/common/services/bulkEdit.ts @@ -9,7 +9,7 @@ import { merge } from 'vs/base/common/arrays'; import { IStringDictionary, forEach, values } from 'vs/base/common/collections'; import URI from 'vs/base/common/uri'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IEditorService } from 'vs/platform/editor/common/editor'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; import { IEventService } from 'vs/platform/event/common/event'; import { EventType as FileEventType, FileChangesEvent, IFileChange } from 'vs/platform/files/common/files'; import { EditOperation } from 'vs/editor/common/core/editOperation'; @@ -157,7 +157,7 @@ class SourceModelEditTask extends EditTask { class BulkEditModel { - private _editorService: IEditorService; + private _textModelResolverService: ITextModelResolverService; private _numberOfResourcesToModify: number = 0; private _numberOfChanges: number = 0; private _edits: IStringDictionary = Object.create(null); @@ -166,8 +166,8 @@ class BulkEditModel { private _sourceSelections: Selection[]; private _sourceModelTask: SourceModelEditTask; - constructor(editorService: IEditorService, sourceModel: URI, sourceSelections: Selection[], edits: IResourceEdit[], private progress: IProgressRunner = null) { - this._editorService = editorService; + constructor(textModelResolverService: ITextModelResolverService, sourceModel: URI, sourceSelections: Selection[], edits: IResourceEdit[], private progress: IProgressRunner = null) { + this._textModelResolverService = textModelResolverService; this._sourceModel = sourceModel; this._sourceSelections = sourceSelections; this._sourceModelTask = null; @@ -209,7 +209,7 @@ class BulkEditModel { } forEach(this._edits, entry => { - var promise = this._editorService.resolveEditorModel({ resource: URI.parse(entry.key) }).then(model => { + var promise = this._textModelResolverService.resolve(URI.parse(entry.key)).then(model => { if (!model || !model.textEditorModel) { throw new Error(`Cannot load file ${entry.key}`); } @@ -260,14 +260,14 @@ export interface BulkEdit { finish(): TPromise; } -export function bulkEdit(eventService: IEventService, editorService: IEditorService, editor: ICommonCodeEditor, edits: IResourceEdit[], progress: IProgressRunner = null): TPromise { - let bulk = createBulkEdit(eventService, editorService, editor); +export function bulkEdit(eventService: IEventService, textModelResolverService: ITextModelResolverService, editor: ICommonCodeEditor, edits: IResourceEdit[], progress: IProgressRunner = null): TPromise { + let bulk = createBulkEdit(eventService, textModelResolverService, editor); bulk.add(edits); bulk.progress(progress); return bulk.finish(); } -export function createBulkEdit(eventService: IEventService, editorService: IEditorService, editor: ICommonCodeEditor): BulkEdit { +export function createBulkEdit(eventService: IEventService, textModelResolverService: ITextModelResolverService, editor: ICommonCodeEditor): BulkEdit { let all: IResourceEdit[] = []; let recording = new ChangeRecorder(eventService).start(); @@ -315,7 +315,7 @@ export function createBulkEdit(eventService: IEventService, editorService: IEdit selections = editor.getSelections(); } - let model = new BulkEditModel(editorService, uri, selections, all, progressRunner); + let model = new BulkEditModel(textModelResolverService, uri, selections, all, progressRunner); return model.prepare().then(_ => { diff --git a/src/vs/editor/common/viewLayout/viewLineParts.ts b/src/vs/editor/common/viewLayout/viewLineParts.ts index 65df90e77b3..c9880cb4481 100644 --- a/src/vs/editor/common/viewLayout/viewLineParts.ts +++ b/src/vs/editor/common/viewLayout/viewLineParts.ts @@ -125,7 +125,7 @@ function insertWhitespaceLineDecorations(lineNumber: number, lineContent: string if (firstNonWhitespaceIndex > fauxIndentLength) { // add leading whitespace state sm_endIndex.push(firstNonWhitespaceIndex - 1); - sm_decoration.push('leading whitespace'); + sm_decoration.push('vs-whitespace'); } @@ -147,7 +147,7 @@ function insertWhitespaceLineDecorations(lineNumber: number, lineContent: string sm_decoration.push(null); sm_endIndex.push(i - 1); - sm_decoration.push('embedded whitespace'); + sm_decoration.push('vs-whitespace'); } startOfWhitespace = -1; @@ -161,7 +161,7 @@ function insertWhitespaceLineDecorations(lineNumber: number, lineContent: string // add trailing whitespace state sm_endIndex.push(lineLength - 1); - sm_decoration.push('trailing whitespace'); + sm_decoration.push('vs-whitespace'); // add dummy state to avoid array length checks sm_endIndex.push(lineLength); diff --git a/src/vs/editor/common/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts index 0d72b1d7fb0..dc1bfe0853c 100644 --- a/src/vs/editor/common/viewLayout/viewLineRenderer.ts +++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts @@ -94,7 +94,7 @@ export function renderLine(input: RenderLineInput): RenderLineOutput { } function isWhitespace(type: string): boolean { - return (type.indexOf('whitespace') >= 0); + return (type.indexOf('vs-whitespace') >= 0); } function isControlCharacter(characterCode: number): boolean { diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index a6b0a628115..da4c5f80205 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -336,7 +336,7 @@ export class ViewModel extends EventEmitter implements IViewModel { } public validateViewRange(viewStartLineNumber: number, viewStartColumn: number, viewEndLineNumber: number, viewEndColumn: number, modelRange: Range): Range { - var validViewStart = this.validateViewPosition(viewStartColumn, viewStartColumn, modelRange.getStartPosition()); + var validViewStart = this.validateViewPosition(viewStartLineNumber, viewStartColumn, modelRange.getStartPosition()); var validViewEnd = this.validateViewPosition(viewEndLineNumber, viewEndColumn, modelRange.getEndPosition()); return new Range(validViewStart.lineNumber, validViewStart.column, validViewEnd.lineNumber, validViewEnd.column); } diff --git a/src/vs/editor/contrib/defineKeybinding/browser/defineKeybinding.ts b/src/vs/editor/contrib/defineKeybinding/browser/defineKeybinding.ts index 05f7a56b581..bb1c32453f8 100644 --- a/src/vs/editor/contrib/defineKeybinding/browser/defineKeybinding.ts +++ b/src/vs/editor/contrib/defineKeybinding/browser/defineKeybinding.ts @@ -110,16 +110,16 @@ export class DefineKeybindingController implements editorCommon.IEditorContribut let snippetText = [ '{', '\t"key": "' + keybinding + '",', - '\t"command": "{{commandId}}",', - '\t"when": "{{editorTextFocus}}"', - '}{{}}' + '\t"command": "${1:commandId}",', + '\t"when": "${2:editorTextFocus}"', + '}$0' ].join('\n'); let smartInsertInfo = SmartSnippetInserter.insertSnippet(this._editor.getModel(), this._editor.getPosition()); snippetText = smartInsertInfo.prepend + snippetText + smartInsertInfo.append; this._editor.setPosition(smartInsertInfo.position); - SnippetController.get(this._editor).run(CodeSnippet.fromInternal(snippetText), 0, 0); + SnippetController.get(this._editor).run(CodeSnippet.fromTextmate(snippetText), 0, 0); } private _onModel(): void { diff --git a/src/vs/editor/contrib/find/common/findController.ts b/src/vs/editor/contrib/find/common/findController.ts index 7524e23644d..cc4087c1107 100644 --- a/src/vs/editor/contrib/find/common/findController.ts +++ b/src/vs/editor/contrib/find/common/findController.ts @@ -474,7 +474,7 @@ export interface IMultiCursorFindResult { currentMatch: Selection; } -function multiCursorFind(editor: editorCommon.ICommonCodeEditor, changeFindSearchString: boolean): IMultiCursorFindResult { +function multiCursorFind(editor: editorCommon.ICommonCodeEditor, changeFindSearchString: boolean, allowMultiline: boolean): IMultiCursorFindResult { let controller = CommonFindController.get(editor); if (!controller) { return null; @@ -498,8 +498,8 @@ function multiCursorFind(editor: editorCommon.ICommonCodeEditor, changeFindSearc // Selection owns what is searched for let s = editor.getSelection(); - if (s.startLineNumber !== s.endLineNumber) { - // Cannot search for multiline string... yet... + if (s.startLineNumber !== s.endLineNumber && !allowMultiline) { + // multiline forbidden return null; } @@ -529,7 +529,7 @@ function multiCursorFind(editor: editorCommon.ICommonCodeEditor, changeFindSearc export abstract class SelectNextFindMatchAction extends EditorAction { protected _getNextMatch(editor: editorCommon.ICommonCodeEditor): Selection { - let r = multiCursorFind(editor, true); + let r = multiCursorFind(editor, /*changeFindSearchString*/true, /*allowMultiline*/true); if (!r) { return null; } @@ -552,7 +552,7 @@ export abstract class SelectNextFindMatchAction extends EditorAction { export abstract class SelectPreviousFindMatchAction extends EditorAction { protected _getPreviousMatch(editor: editorCommon.ICommonCodeEditor): Selection { - let r = multiCursorFind(editor, true); + let r = multiCursorFind(editor, /*changeFindSearchString*/true, /*allowMultiline*/true); if (!r) { return null; } @@ -683,7 +683,7 @@ export class MoveSelectionToPreviousFindMatchAction extends SelectPreviousFindMa export abstract class AbstractSelectHighlightsAction extends EditorAction { public run(accessor: ServicesAccessor, editor: editorCommon.ICommonCodeEditor): void { - let r = multiCursorFind(editor, true); + let r = multiCursorFind(editor, /*changeFindSearchString*/true, /*allowMultiline*/true); if (!r) { return; } @@ -805,7 +805,7 @@ export class SelectionHighlighter extends Disposable implements editorCommon.IEd return; } - let r = multiCursorFind(this.editor, false); + let r = multiCursorFind(this.editor, /*changeFindSearchString*/false, /*allowMultiline*/false); if (!r) { this.removeDecorations(); return; diff --git a/src/vs/editor/contrib/find/test/common/findController.test.ts b/src/vs/editor/contrib/find/test/common/findController.test.ts index 4225d6410b2..3345b1bd131 100644 --- a/src/vs/editor/contrib/find/test/common/findController.test.ts +++ b/src/vs/editor/contrib/find/test/common/findController.test.ts @@ -12,7 +12,8 @@ import { Range } from 'vs/editor/common/core/range'; import { IRange } from 'vs/editor/common/editorCommon'; import { CommonFindController, FindStartFocusAction, IFindStartOptions, - NextMatchFindAction, StartFindAction, SelectHighlightsAction + NextMatchFindAction, StartFindAction, SelectHighlightsAction, + AddSelectionToNextFindMatchAction } from 'vs/editor/contrib/find/common/findController'; import { withMockCodeEditor } from 'vs/editor/test/common/mocks/mockCodeEditor'; import { HistoryNavigator } from 'vs/base/common/history'; @@ -317,6 +318,38 @@ suite('FindController', () => { }); }); + test('AddSelectionToNextFindMatchAction can work with multiline', () => { + withMockCodeEditor([ + '', + 'qwe', + 'rty', + '', + 'qwe', + '', + 'rty', + 'qwe', + 'rty' + ], {}, (editor, cursor) => { + + let findController = editor.registerAndInstantiateContribution(TestFindController); + let addSelectionToNextFindMatch = new AddSelectionToNextFindMatchAction(); + + editor.setSelection(new Selection(2, 1, 3, 4)); + + addSelectionToNextFindMatch.run(null, editor); + assert.deepEqual(editor.getSelections().map(fromRange), [ + [2, 1, 3, 4], + [8, 1, 9, 4] + ]); + + editor.trigger('test', 'removeSecondaryCursors', null); + + assert.deepEqual(fromRange(editor.getSelection()), [2, 1, 3, 4]); + + findController.dispose(); + }); + }); + function toArray(historyNavigator: HistoryNavigator): string[] { let result = []; historyNavigator.first(); diff --git a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts index 2c33ea87f67..cd71f592581 100644 --- a/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts +++ b/src/vs/editor/contrib/goToDeclaration/browser/goToDeclaration.ts @@ -32,6 +32,7 @@ import { ReferencesModel } from 'vs/editor/contrib/referenceSearch/browser/refer import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { PeekContext } from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; import ModeContextKeys = editorCommon.ModeContextKeys; import EditorContextKeys = editorCommon.EditorContextKeys; @@ -233,7 +234,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC constructor( editor: ICodeEditor, - @IEditorService private editorService: IEditorService, + @ITextModelResolverService private textModelResolverService: ITextModelResolverService, @IModeService private modeService: IModeService ) { this.toUnhook = []; @@ -318,7 +319,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC // Single result else { let result = results[0]; - this.editorService.resolveEditorModel({ resource: result.uri }).then(model => { + this.textModelResolverService.resolve(result.uri).then(model => { let hoverMessage: MarkedString; if (model && model.textEditorModel) { const editorModel = model.textEditorModel; diff --git a/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts b/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts index d66c428b668..173ff1ed5e7 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referencesController.ts @@ -25,6 +25,7 @@ import { IPeekViewService } from 'vs/editor/contrib/zoneWidget/browser/peekViewW import { ReferencesModel, OneReference } from './referencesModel'; import { ReferenceWidget, LayoutData } from './referencesWidget'; import { Range } from 'vs/editor/common/core/range'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; export const ctxReferenceSearchVisible = new RawContextKey('referenceSearchVisible', false); @@ -55,6 +56,7 @@ export class ReferencesController implements editorCommon.IEditorContribution { editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, @IEditorService private _editorService: IEditorService, + @ITextModelResolverService private _textModelResolverService, @ITelemetryService private _telemetryService: ITelemetryService, @IMessageService private _messageService: IMessageService, @IInstantiationService private _instantiationService: IInstantiationService, @@ -102,7 +104,7 @@ export class ReferencesController implements editorCommon.IEditorContribution { })); const storageKey = 'peekViewLayout'; const data = JSON.parse(this._storageService.get(storageKey, undefined, '{}')); - this._widget = new ReferenceWidget(this._editor, data, this._editorService, this._contextService, this._instantiationService); + this._widget = new ReferenceWidget(this._editor, data, this._textModelResolverService, this._contextService, this._instantiationService); this._widget.setTitle(nls.localize('labelLoading', "Loading...")); this._widget.show(range); this._disposables.push(this._widget.onDidClose(() => { diff --git a/src/vs/editor/contrib/referenceSearch/browser/referencesModel.ts b/src/vs/editor/contrib/referenceSearch/browser/referencesModel.ts index 453b72c5183..08bdb6ba950 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referencesModel.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referencesModel.ts @@ -11,10 +11,10 @@ import * as strings from 'vs/base/common/strings'; import URI from 'vs/base/common/uri'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IEditorService } from 'vs/platform/editor/common/editor'; import { Range } from 'vs/editor/common/core/range'; import { IModel, IPosition, IRange } from 'vs/editor/common/editorCommon'; import { Location } from 'vs/editor/common/modes'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; export class OneReference { @@ -128,13 +128,13 @@ export class FileReferences { return this._loadFailure; } - public resolve(editorService: IEditorService): TPromise { + public resolve(textModelResolverService: ITextModelResolverService): TPromise { if (this._resolved) { return TPromise.as(this); } - return editorService.resolveEditorModel({ resource: this._uri }).then(model => { + return textModelResolverService.resolve(this._uri).then(model => { if (!model) { throw new Error(); } diff --git a/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts index f409b0614a2..8e06439ef2e 100644 --- a/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/browser/referencesWidget.ts @@ -26,7 +26,6 @@ import { LeftRightWidget } from 'vs/base/browser/ui/leftRightWidget/leftRightWid import * as tree from 'vs/base/parts/tree/browser/tree'; import { DefaultController, LegacyRenderer } from 'vs/base/parts/tree/browser/treeDefaults'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; -import { IEditorService } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -38,6 +37,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget'; import { PeekViewWidget, IPeekViewService } from 'vs/editor/contrib/zoneWidget/browser/peekViewWidget'; import { FileReferences, OneReference, ReferencesModel } from './referencesModel'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; class DecorationsManager implements IDisposable { @@ -165,7 +165,7 @@ class DecorationsManager implements IDisposable { class DataSource implements tree.IDataSource { constructor( - @IEditorService private _editorService: IEditorService + @ITextModelResolverService private _textModelResolverService: ITextModelResolverService ) { // } @@ -193,7 +193,7 @@ class DataSource implements tree.IDataSource { if (element instanceof ReferencesModel) { return TPromise.as(element.groups); } else if (element instanceof FileReferences) { - return element.resolve(this._editorService).then(val => { + return element.resolve(this._textModelResolverService).then(val => { if (element.failure) { // refresh the element on failure so that // we can update its rendering @@ -501,7 +501,7 @@ export class ReferenceWidget extends PeekViewWidget { constructor( editor: ICodeEditor, public layoutData: LayoutData, - private _editorService: IEditorService, + private _textModelResolverService: ITextModelResolverService, private _contextService: IWorkspaceContextService, private _instantiationService: IInstantiationService ) { @@ -716,7 +716,7 @@ export class ReferenceWidget extends PeekViewWidget { } return TPromise.join([ - this._editorService.resolveEditorModel({ resource: reference.uri }), + this._textModelResolverService.resolve(reference.uri), this._tree.reveal(reference) ]).then(values => { if (!this._model) { diff --git a/src/vs/editor/contrib/rename/browser/rename.ts b/src/vs/editor/contrib/rename/browser/rename.ts index 444f24f59bc..3ac12299540 100644 --- a/src/vs/editor/contrib/rename/browser/rename.ts +++ b/src/vs/editor/contrib/rename/browser/rename.ts @@ -10,7 +10,6 @@ import { isPromiseCanceledError } from 'vs/base/common/errors'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IEditorService } from 'vs/platform/editor/common/editor'; import { IEventService } from 'vs/platform/event/common/event'; import { RawContextKey, IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -22,6 +21,7 @@ import { BulkEdit, createBulkEdit } from 'vs/editor/common/services/bulkEdit'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { rename } from '../common/rename'; import RenameInputField from './renameInputField'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; // --- register actions and commands @@ -43,7 +43,7 @@ class RenameController implements IEditorContribution { private editor: ICodeEditor, @IMessageService private _messageService: IMessageService, @IEventService private _eventService: IEventService, - @IEditorService private _editorService: IEditorService, + @ITextModelResolverService private _textModelResolverService: ITextModelResolverService, @IProgressService private _progressService: IProgressService, @IContextKeyService contextKeyService: IContextKeyService ) { @@ -132,7 +132,7 @@ class RenameController implements IEditorContribution { // start recording of file changes so that we can figure out if a file that // is to be renamed conflicts with another (concurrent) modification - let edit = createBulkEdit(this._eventService, this._editorService, this.editor); + let edit = createBulkEdit(this._eventService, this._textModelResolverService, this.editor); return rename(this.editor.getModel(), this.editor.getPosition(), newName).then(result => { if (result.rejectReason) { diff --git a/src/vs/editor/contrib/snippet/common/snippet.ts b/src/vs/editor/contrib/snippet/common/snippet.ts index 94b4bdec13c..a86eaf569a1 100644 --- a/src/vs/editor/contrib/snippet/common/snippet.ts +++ b/src/vs/editor/contrib/snippet/common/snippet.ts @@ -159,7 +159,7 @@ const InternalFormatSnippetParser = new class implements ISnippetParser { private parseTemplate(template: string): void { - var placeHoldersMap: collections.IStringDictionary = {}; + var placeHoldersMap: collections.IStringDictionary = Object.create(null); var i: number, len: number, j: number, lenJ: number, templateLines = template.split('\n'); for (i = 0, len = templateLines.length; i < len; i++) { @@ -226,12 +226,25 @@ const InternalFormatSnippetParser = new class implements ISnippetParser { } } - private parseLine(line: string, findDefaultValueForId: (id: string) => string): IParsedLine { + private parseLine(line: string, findDefaultValueForIdFromPrevLines: (id: string) => string): IParsedLine { // Placeholder 0 is the entire line var placeHolderStack: { placeHolderId: string; placeHolderText: string; }[] = [{ placeHolderId: '', placeHolderText: '' }]; var placeHolders: IParsedLinePlaceHolderInfo[] = []; + const findDefaultValueForId = (id) => { + const result = findDefaultValueForIdFromPrevLines(id); + if (result) { + return result; + } + for (const placeHolder of placeHolders) { + if (placeHolder.id === id && placeHolder.value) { + return placeHolder.value; + } + } + return ''; + }; + var i = 0; var len = line.length; var resultIndex = 0; diff --git a/src/vs/editor/contrib/snippet/common/snippetController.ts b/src/vs/editor/contrib/snippet/common/snippetController.ts index 13fb2b1343c..f7dc47e6cc5 100644 --- a/src/vs/editor/contrib/snippet/common/snippetController.ts +++ b/src/vs/editor/contrib/snippet/common/snippetController.ts @@ -443,25 +443,6 @@ export class SnippetController { } } - private static _getTypeRangeForSelection(model: editorCommon.IModel, selection: Selection, overwriteBefore: number, overwriteAfter: number): Range { - var typeRange: Range; - if (overwriteBefore || overwriteAfter) { - typeRange = model.validateRange(Range.plusRange(selection, { - startLineNumber: selection.positionLineNumber, - startColumn: selection.positionColumn - overwriteBefore, - endLineNumber: selection.positionLineNumber, - endColumn: selection.positionColumn + overwriteAfter - })); - } else { - typeRange = selection; - } - return typeRange; - } - - private static _getAdaptedSnippet(model: editorCommon.IModel, snippet: CodeSnippet, typeRange: Range): ICodeSnippet { - return snippet.bind(model.getLineContent(typeRange.startLineNumber), typeRange.startLineNumber - 1, typeRange.startColumn - 1, model); - } - private static _addCommandForSnippet(model: editorCommon.ITextModel, adaptedSnippet: ICodeSnippet, typeRange: Range, out: editorCommon.IIdentifiedSingleEditOperation[]): void { let insertText = adaptedSnippet.lines.join('\n'); let currentText = model.getValueInRange(typeRange, editorCommon.EndOfLinePreference.LF); @@ -603,6 +584,25 @@ export class SnippetController { }; } + private static _getTypeRangeForSelection(model: editorCommon.IModel, selection: Selection, overwriteBefore: number, overwriteAfter: number): Range { + var typeRange: Range; + if (overwriteBefore || overwriteAfter) { + typeRange = model.validateRange(Range.plusRange(selection, { + startLineNumber: selection.positionLineNumber, + startColumn: selection.positionColumn - overwriteBefore, + endLineNumber: selection.positionLineNumber, + endColumn: selection.positionColumn + overwriteAfter + })); + } else { + typeRange = selection; + } + return typeRange; + } + + private static _getAdaptedSnippet(model: editorCommon.IModel, snippet: CodeSnippet, typeRange: Range): ICodeSnippet { + return snippet.bind(model.getLineContent(typeRange.startLineNumber), typeRange.startLineNumber - 1, typeRange.startColumn - 1, model); + } + private static _getSnippetCursorOnly(snippet: ICodeSnippet): editorCommon.IPosition { if (snippet.placeHolders.length !== 1) { diff --git a/src/vs/editor/contrib/snippet/test/common/snippet.test.ts b/src/vs/editor/contrib/snippet/test/common/snippet.test.ts index 096ff741722..e8a38c91f6f 100644 --- a/src/vs/editor/contrib/snippet/test/common/snippet.test.ts +++ b/src/vs/editor/contrib/snippet/test/common/snippet.test.ts @@ -141,6 +141,16 @@ suite('Editor Contrib - Snippets', () => { }); }); + test('bug #7093: Snippet default value is only populated for first variable reference', () => { + var internal = 'logger.error({ logContext: lc, errorContext: `{{1:err}}`, error: {{1:}} });'; + var external = 'logger.error({ logContext: lc, errorContext: `${1:err}`, error: $1 });'; + + assertInternalAndTextmate(internal, external, snippet => { + assert.equal(snippet.lines.length, 1); + assert.equal(snippet.lines[0], 'logger.error({ logContext: lc, errorContext: `err`, error: err });'); + }); + }); + test('bug #17487:[snippets] four backslashes are required to get one backslash in the inserted text', () => { var external = [ diff --git a/src/vs/editor/contrib/suggest/browser/suggestController.ts b/src/vs/editor/contrib/suggest/browser/suggestController.ts index 3fc842becd8..f607f00aadf 100644 --- a/src/vs/editor/contrib/suggest/browser/suggestController.ts +++ b/src/vs/editor/contrib/suggest/browser/suggestController.ts @@ -105,6 +105,17 @@ export class SuggestController implements IEditorContribution { this.telemetryService.publicLog('suggestSnippetInsert', { hasPlaceholders: snippet.placeHolders.length > 0 }); + + // telemetry experiment to figure out which extensions use + // the internal snippet syntax today and which use the tm + // snippet syntax (by accident?) + if (suggestion._extensionId) { + this.telemetryService.publicLog('suggestSnippetInsert2', { + extension: suggestion._extensionId, + internalPlaceholders: snippet.placeHolders.length, + tmPlaceholders: CodeSnippet.fromTextmate(suggestion.insertText).placeHolders.length + }); + } } } diff --git a/src/vs/editor/contrib/suggest/test/common/completionModel.test.ts b/src/vs/editor/contrib/suggest/test/common/completionModel.test.ts index 58e189f5408..6c5acc76586 100644 --- a/src/vs/editor/contrib/suggest/test/common/completionModel.test.ts +++ b/src/vs/editor/contrib/suggest/test/common/completionModel.test.ts @@ -143,5 +143,9 @@ suite('CompletionModel', function () { assertTopScore('Editor.r', 0, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace'); assertTopScore('-mo', 1, '-ms-ime-mode', '-moz-columns'); + // dupe, issue #14861 + assertTopScore('convertModelPosition', 0, 'convertModelPositionToViewPosition', 'convertViewToModelPosition'); + // dupe, issue #14942 + assertTopScore('is', 0, 'isValidViewletId', 'import statement'); }); }); diff --git a/src/vs/editor/test/common/controller/cursor.test.ts b/src/vs/editor/test/common/controller/cursor.test.ts index 67b78a3f9ab..b9a41cc628c 100644 --- a/src/vs/editor/test/common/controller/cursor.test.ts +++ b/src/vs/editor/test/common/controller/cursor.test.ts @@ -2726,3 +2726,165 @@ function usingCursor(opts: ICursorOpts, callback: (model: Model, cursor: Cursor) config.dispose(); model.dispose(); } + +class ElectricCharMode extends MockMode { + constructor() { + super(); + LanguageConfigurationRegistry.register(this.getId(), { + __electricCharacterSupport: { + docComment: { open: '/**', close: ' */' } + }, + brackets: [ + ['{', '}'], + ['[', ']'], + ['(', ')'] + ] + }); + } +} + +suite('ElectricCharacter', () => { + test('does nothing if no electric char', () => { + usingCursor({ + text: [ + ' if (a) {', + '' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 2, 1); + cursorCommand(cursor, H.Type, { text: '*' }, 'keyboard'); + assert.deepEqual(model.getLineContent(2), '*'); + }); + }); + + test('indents in order to match bracket', () => { + usingCursor({ + text: [ + ' if (a) {', + '' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 2, 1); + cursorCommand(cursor, H.Type, { text: '}' }, 'keyboard'); + assert.deepEqual(model.getLineContent(2), ' }'); + }); + }); + + test('unindents in order to match bracket', () => { + usingCursor({ + text: [ + ' if (a) {', + ' ' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 2, 5); + cursorCommand(cursor, H.Type, { text: '}' }, 'keyboard'); + assert.deepEqual(model.getLineContent(2), ' }'); + }); + }); + + test('matches with correct bracket', () => { + usingCursor({ + text: [ + ' if (a) {', + ' if (b) {', + ' }', + ' ' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 4, 1); + cursorCommand(cursor, H.Type, { text: '}' }, 'keyboard'); + assert.deepEqual(model.getLineContent(4), ' } '); + }); + }); + + test('does nothing if bracket does not match', () => { + usingCursor({ + text: [ + ' if (a) {', + ' if (b) {', + ' }', + ' } ' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 4, 6); + cursorCommand(cursor, H.Type, { text: '}' }, 'keyboard'); + assert.deepEqual(model.getLineContent(4), ' } }'); + }); + }); + + test('matches bracket even in line with content', () => { + usingCursor({ + text: [ + ' if (a) {', + '// hello' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 2, 1); + cursorCommand(cursor, H.Type, { text: '}' }, 'keyboard'); + assert.deepEqual(model.getLineContent(2), ' }// hello'); + }); + }); + + test('is no-op if bracket is lined up', () => { + usingCursor({ + text: [ + ' if (a) {', + ' ' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 2, 3); + cursorCommand(cursor, H.Type, { text: '}' }, 'keyboard'); + assert.deepEqual(model.getLineContent(2), ' }'); + }); + }); + + test('is no-op if there is non-whitespace text before', () => { + usingCursor({ + text: [ + ' if (a) {', + 'a' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 2, 2); + cursorCommand(cursor, H.Type, { text: '}' }, 'keyboard'); + assert.deepEqual(model.getLineContent(2), ' a}'); + }); + }); + + test('appends text', () => { + usingCursor({ + text: [ + ' if (a) {', + '/*' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 2, 3); + cursorCommand(cursor, H.Type, { text: '*' }, 'keyboard'); + assert.deepEqual(model.getLineContent(2), '/** */'); + }); + }); + + test('appends text 2', () => { + usingCursor({ + text: [ + ' if (a) {', + ' /*' + ], + modeId: new ElectricCharMode().getId() + }, (model, cursor) => { + moveTo(cursor, 2, 5); + cursorCommand(cursor, H.Type, { text: '*' }, 'keyboard'); + assert.deepEqual(model.getLineContent(2), ' /** */'); + }); + }); +}); diff --git a/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts b/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts index 8ff1e854911..4b450f62d3c 100644 --- a/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts +++ b/src/vs/editor/test/common/controller/cursorMoveHelper.test.ts @@ -5,90 +5,46 @@ 'use strict'; import * as assert from 'assert'; -import * as strings from 'vs/base/common/strings'; -import { CursorMoveHelper, ICursorMoveHelperModel, CursorMoveConfiguration } from 'vs/editor/common/controller/cursorMoveHelper'; +import { CursorColumns } from 'vs/editor/common/controller/cursorCommon'; suite('CursorMove', () => { test('nextTabStop', () => { - assert.equal(CursorMoveHelper.nextTabColumn(0, 4), 4); - assert.equal(CursorMoveHelper.nextTabColumn(1, 4), 4); - assert.equal(CursorMoveHelper.nextTabColumn(2, 4), 4); - assert.equal(CursorMoveHelper.nextTabColumn(3, 4), 4); - assert.equal(CursorMoveHelper.nextTabColumn(4, 4), 8); - assert.equal(CursorMoveHelper.nextTabColumn(5, 4), 8); - assert.equal(CursorMoveHelper.nextTabColumn(6, 4), 8); - assert.equal(CursorMoveHelper.nextTabColumn(7, 4), 8); - assert.equal(CursorMoveHelper.nextTabColumn(8, 4), 12); + assert.equal(CursorColumns.nextTabStop(0, 4), 4); + assert.equal(CursorColumns.nextTabStop(1, 4), 4); + assert.equal(CursorColumns.nextTabStop(2, 4), 4); + assert.equal(CursorColumns.nextTabStop(3, 4), 4); + assert.equal(CursorColumns.nextTabStop(4, 4), 8); + assert.equal(CursorColumns.nextTabStop(5, 4), 8); + assert.equal(CursorColumns.nextTabStop(6, 4), 8); + assert.equal(CursorColumns.nextTabStop(7, 4), 8); + assert.equal(CursorColumns.nextTabStop(8, 4), 12); - assert.equal(CursorMoveHelper.nextTabColumn(0, 2), 2); - assert.equal(CursorMoveHelper.nextTabColumn(1, 2), 2); - assert.equal(CursorMoveHelper.nextTabColumn(2, 2), 4); - assert.equal(CursorMoveHelper.nextTabColumn(3, 2), 4); - assert.equal(CursorMoveHelper.nextTabColumn(4, 2), 6); - assert.equal(CursorMoveHelper.nextTabColumn(5, 2), 6); - assert.equal(CursorMoveHelper.nextTabColumn(6, 2), 8); - assert.equal(CursorMoveHelper.nextTabColumn(7, 2), 8); - assert.equal(CursorMoveHelper.nextTabColumn(8, 2), 10); + assert.equal(CursorColumns.nextTabStop(0, 2), 2); + assert.equal(CursorColumns.nextTabStop(1, 2), 2); + assert.equal(CursorColumns.nextTabStop(2, 2), 4); + assert.equal(CursorColumns.nextTabStop(3, 2), 4); + assert.equal(CursorColumns.nextTabStop(4, 2), 6); + assert.equal(CursorColumns.nextTabStop(5, 2), 6); + assert.equal(CursorColumns.nextTabStop(6, 2), 8); + assert.equal(CursorColumns.nextTabStop(7, 2), 8); + assert.equal(CursorColumns.nextTabStop(8, 2), 10); - assert.equal(CursorMoveHelper.nextTabColumn(0, 1), 1); - assert.equal(CursorMoveHelper.nextTabColumn(1, 1), 2); - assert.equal(CursorMoveHelper.nextTabColumn(2, 1), 3); - assert.equal(CursorMoveHelper.nextTabColumn(3, 1), 4); - assert.equal(CursorMoveHelper.nextTabColumn(4, 1), 5); - assert.equal(CursorMoveHelper.nextTabColumn(5, 1), 6); - assert.equal(CursorMoveHelper.nextTabColumn(6, 1), 7); - assert.equal(CursorMoveHelper.nextTabColumn(7, 1), 8); - assert.equal(CursorMoveHelper.nextTabColumn(8, 1), 9); + assert.equal(CursorColumns.nextTabStop(0, 1), 1); + assert.equal(CursorColumns.nextTabStop(1, 1), 2); + assert.equal(CursorColumns.nextTabStop(2, 1), 3); + assert.equal(CursorColumns.nextTabStop(3, 1), 4); + assert.equal(CursorColumns.nextTabStop(4, 1), 5); + assert.equal(CursorColumns.nextTabStop(5, 1), 6); + assert.equal(CursorColumns.nextTabStop(6, 1), 7); + assert.equal(CursorColumns.nextTabStop(7, 1), 8); + assert.equal(CursorColumns.nextTabStop(8, 1), 9); }); - class OneLineModel implements ICursorMoveHelperModel { - private _line: string; - - constructor(line: string) { - this._line = line; - } - - getLineCount(): number { - return 1; - } - - getLineContent(lineNumber: number): string { - return this._line; - } - - getLineMinColumn(lineNumber: number): number { - return 1; - } - - getLineMaxColumn(lineNumber: number): number { - return this._line.length + 1; - } - - getLineFirstNonWhitespaceColumn(lineNumber: number): number { - let result = strings.firstNonWhitespaceIndex(this._line); - if (result === -1) { - return 0; - } - return result + 1; - } - - getLineLastNonWhitespaceColumn(lineNumber: number): number { - let result = strings.lastNonWhitespaceIndex(this._line); - if (result === -1) { - return 0; - } - return result + 2; - } - - } - test('visibleColumnFromColumn', () => { - function testVisibleColumnFromColumn(text:string, tabSize:number, column:number, expected:number): void { - let helper = new CursorMoveHelper(new CursorMoveConfiguration(tabSize, 13)); - let model = new OneLineModel(text); - assert.equal(helper.visibleColumnFromColumn(model, 1, column), expected); + function testVisibleColumnFromColumn(text: string, tabSize: number, column: number, expected: number): void { + assert.equal(CursorColumns.visibleColumnFromColumn(text, column, tabSize), expected); } testVisibleColumnFromColumn('\t\tvar x = 3;', 4, 1, 0); @@ -146,10 +102,8 @@ suite('CursorMove', () => { test('columnFromVisibleColumn', () => { - function testColumnFromVisibleColumn(text:string, tabSize:number, visibleColumn:number, expected:number): void { - let helper = new CursorMoveHelper(new CursorMoveConfiguration(tabSize, 13)); - let model = new OneLineModel(text); - assert.equal(helper.columnFromVisibleColumn(model, 1, visibleColumn), expected); + function testColumnFromVisibleColumn(text: string, tabSize: number, visibleColumn: number, expected: number): void { + assert.equal(CursorColumns.columnFromVisibleColumn(text, visibleColumn, tabSize), expected); } // testColumnFromVisibleColumn('\t\tvar x = 3;', 4, 0, 1); diff --git a/src/vs/editor/test/common/editorTestUtils.ts b/src/vs/editor/test/common/editorTestUtils.ts index a1debaa84cc..52665e7da15 100644 --- a/src/vs/editor/test/common/editorTestUtils.ts +++ b/src/vs/editor/test/common/editorTestUtils.ts @@ -33,13 +33,10 @@ export function viewModelHelper(model): IViewModelHelper { convertViewSelectionToModelSelection: (viewSelection: Selection) => { return viewSelection; }, - convertViewRangeToModelRange: (modelRange: Range) => { - return modelRange; - }, - validateViewPosition: (viewLineNumber: number, viewColumn: number, modelPosition: Position) => { + validateViewPosition: (viewPosition: Position, modelPosition: Position): Position => { return modelPosition; }, - validateViewRange: (viewStartLineNumber: number, viewStartColumn: number, viewEndLineNumber: number, viewEndColumn: number, modelRange: Range) => { + validateViewRange: (viewRange:Range, modelRange: Range): Range => { return modelRange; } }; diff --git a/src/vs/editor/test/common/model/model.test.ts b/src/vs/editor/test/common/model/model.test.ts index 9e1e6758b3c..ef0838928cc 100644 --- a/src/vs/editor/test/common/model/model.test.ts +++ b/src/vs/editor/test/common/model/model.test.ts @@ -690,6 +690,23 @@ suite('Editor Model - Find', () => { ); }); + test('multiline find for non-regex string', () => { + assertFindMatches( + [ + 'Just some text text', + 'some text text', + 'some text again', + 'again some text', + 'but not some' + ].join('\n'), + 'text\nsome', false, false, false, + [ + [1, 16, 2, 5], + [2, 11, 3, 5], + ] + ); + }); + test('findNextMatch without regex', () => { var testObject = new TextModel([], TextModel.toRawText('line line one\nline two\nthree', TextModel.DEFAULT_CREATION_OPTIONS)); diff --git a/src/vs/editor/test/common/modes/supports/characterPair.test.ts b/src/vs/editor/test/common/modes/supports/characterPair.test.ts index 85ebdaecd37..2bcf2d5c70a 100644 --- a/src/vs/editor/test/common/modes/supports/characterPair.test.ts +++ b/src/vs/editor/test/common/modes/supports/characterPair.test.ts @@ -52,70 +52,70 @@ suite('CharacterPairSupport', () => { assert.deepEqual(characaterPairSupport.getSurroundingPairs(), []); }); - function testShouldAutoClose(characterPairSupport: CharacterPairSupport, line: TokenText[], character: string, offset: number): boolean { - return characterPairSupport.shouldAutoClosePair(character, createFakeScopedLineTokens('test', line), offset); + function testShouldAutoClose(characterPairSupport: CharacterPairSupport, line: TokenText[], character: string, column: number): boolean { + return characterPairSupport.shouldAutoClosePair(character, createFakeScopedLineTokens('test', line), column); } test('shouldAutoClosePair in empty line', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); - assert.equal(testShouldAutoClose(sup, [], 'a', 0), true); - assert.equal(testShouldAutoClose(sup, [], '{', 0), true); + assert.equal(testShouldAutoClose(sup, [], 'a', 1), true); + assert.equal(testShouldAutoClose(sup, [], '{', 1), true); }); test('shouldAutoClosePair in not interesting line 1', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); - assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'keyword' }], '{', 2), true); - assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'keyword' }], 'a', 2), true); + assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'keyword' }], '{', 3), true); + assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'keyword' }], 'a', 3), true); }); test('shouldAutoClosePair in not interesting line 2', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}' }] }); - assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'string' }], '{', 2), true); - assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'string' }], 'a', 2), true); + assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'string' }], '{', 3), true); + assert.equal(testShouldAutoClose(sup, [{ text: 'do', type: 'string' }], 'a', 3), true); }); test('shouldAutoClosePair in interesting line 1', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); - assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], '{', 0), false); - assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], 'a', 0), true); assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], '{', 1), false); assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], 'a', 1), true); assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], '{', 2), false); assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], 'a', 2), true); assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], '{', 3), false); assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], 'a', 3), true); + assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], '{', 4), false); + assert.equal(testShouldAutoClose(sup, [{ text: '"a"', type: 'string' }], 'a', 4), true); }); test('shouldAutoClosePair in interesting line 2', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); - assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 0), true); - assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], 'a', 0), true); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 1), true); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], 'a', 1), true); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 2), true); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], 'a', 2), true); - assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 3), false); + assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 3), true); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], 'a', 3), true); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 4), false); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], 'a', 4), true); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 5), false); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], 'a', 5), true); - assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 6), true); + assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 6), false); assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], 'a', 6), true); + assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], '{', 7), true); + assert.equal(testShouldAutoClose(sup, [{ text: 'x=', type: 'op' }, { text: '"a"', type: 'string' }, { text: ';', type: 'punct' }], 'a', 7), true); }); test('shouldAutoClosePair in interesting line 3', () => { let sup = new CharacterPairSupport({ autoClosingPairs: [{ open: '{', close: '}', notIn: ['string', 'comment'] }] }); - assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], '{', 0), true); - assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], 'a', 0), true); assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], '{', 1), true); assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], 'a', 1), true); - assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], '{', 2), false); + assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], '{', 2), true); assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], 'a', 2), true); assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], '{', 3), false); assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], 'a', 3), true); assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], '{', 4), false); assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], 'a', 4), true); + assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], '{', 5), false); + assert.equal(testShouldAutoClose(sup, [{ text: ' ', type: '' }, { text: '//a', type: 'comment' }], 'a', 5), true); }); }); diff --git a/src/vs/editor/test/common/modes/supports/electricCharacter.test.ts b/src/vs/editor/test/common/modes/supports/electricCharacter.test.ts index 1dcb2ffcae7..ab4733df599 100644 --- a/src/vs/editor/test/common/modes/supports/electricCharacter.test.ts +++ b/src/vs/editor/test/common/modes/supports/electricCharacter.test.ts @@ -10,22 +10,22 @@ import { createFakeScopedLineTokens, TokenText } from 'vs/editor/test/common/mod import { RichEditBrackets } from 'vs/editor/common/modes/supports/richEditBrackets'; suite('Editor Modes - Auto Indentation', () => { - function _testOnElectricCharacter(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], offset: number): IElectricAction { - return electricCharacterSupport.onElectricCharacter(createFakeScopedLineTokens('test', line), offset); + function _testOnElectricCharacter(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number): IElectricAction { + return electricCharacterSupport.onElectricCharacter(character, createFakeScopedLineTokens('test', line), offset); } - function testDoesNothing(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], offset: number): void { - let actual = _testOnElectricCharacter(electricCharacterSupport, line, offset); + function testDoesNothing(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number): void { + let actual = _testOnElectricCharacter(electricCharacterSupport, line, character, offset); assert.deepEqual(actual, null); } - function testAppends(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], offset: number, appendText: string): void { - let actual = _testOnElectricCharacter(electricCharacterSupport, line, offset); + function testAppends(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number, appendText: string): void { + let actual = _testOnElectricCharacter(electricCharacterSupport, line, character, offset); assert.deepEqual(actual, { appendText: appendText }); } - function testMatchBracket(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], offset: number, matchOpenBracket: string): void { - let actual = _testOnElectricCharacter(electricCharacterSupport, line, offset); + function testMatchBracket(electricCharacterSupport: BracketElectricCharacterSupport, line: TokenText[], character: string, offset: number, matchOpenBracket: string): void { + let actual = _testOnElectricCharacter(electricCharacterSupport, line, character, offset); assert.deepEqual(actual, { matchOpenBracket: matchOpenBracket }); } @@ -33,14 +33,14 @@ suite('Editor Modes - Auto Indentation', () => { var brackets = new BracketElectricCharacterSupport(null, [{ open: '/**', close: ' */' }], null); testAppends(brackets, [ - { text: '/**', type: 'doc' }, - ], 2, ' */'); + { text: '/*', type: 'doc' }, + ], '*', 3, ' */'); testDoesNothing(brackets, [ - { text: '/**', type: 'doc' }, + { text: '/*', type: 'doc' }, { text: ' ', type: 'doc' }, { text: '*/', type: 'doc' }, - ], 2); + ], '*', 3); }); test('getElectricCharacters uses all sources and dedups', () => { @@ -72,36 +72,33 @@ suite('Editor Modes - Auto Indentation', () => { { docComment: { open: '/**', close: ' */' } } ); - testDoesNothing(sup, [], 0); + testDoesNothing(sup, [], 'a', 0); - testDoesNothing(sup, [{ text: 'begi', type: '' }], 0); - testDoesNothing(sup, [{ text: 'begi', type: '' }], 1); - testDoesNothing(sup, [{ text: 'begi', type: '' }], 2); - testDoesNothing(sup, [{ text: 'begi', type: '' }], 3); - testDoesNothing(sup, [{ text: 'begi', type: '' }], 4); + testDoesNothing(sup, [{ text: 'egi', type: '' }], 'b', 1); + testDoesNothing(sup, [{ text: 'bgi', type: '' }], 'e', 2); + testDoesNothing(sup, [{ text: 'bei', type: '' }], 'g', 3); + testDoesNothing(sup, [{ text: 'beg', type: '' }], 'i', 4); - testDoesNothing(sup, [{ text: 'begin', type: '' }], 0); - testDoesNothing(sup, [{ text: 'begin', type: '' }], 1); - testDoesNothing(sup, [{ text: 'begin', type: '' }], 2); - testDoesNothing(sup, [{ text: 'begin', type: '' }], 3); - testAppends(sup, [{ text: 'begin', type: '' }], 4, 'end'); - testDoesNothing(sup, [{ text: 'begin', type: '' }], 5); + testDoesNothing(sup, [{ text: 'egin', type: '' }], 'b', 1); + testDoesNothing(sup, [{ text: 'bgin', type: '' }], 'e', 2); + testDoesNothing(sup, [{ text: 'bein', type: '' }], 'g', 3); + testDoesNothing(sup, [{ text: 'begn', type: '' }], 'i', 4); + testAppends(sup, [{ text: 'begi', type: '' }], 'n', 5, 'end'); - testDoesNothing(sup, [{ text: 'b3gin', type: '' }], 0); - testDoesNothing(sup, [{ text: 'b3gin', type: '' }], 1); - testDoesNothing(sup, [{ text: 'b3gin', type: '' }], 2); - testDoesNothing(sup, [{ text: 'b3gin', type: '' }], 3); - testDoesNothing(sup, [{ text: 'b3gin', type: '' }], 4); - testDoesNothing(sup, [{ text: 'b3gin', type: '' }], 5); + testDoesNothing(sup, [{ text: '3gin', type: '' }], 'b', 1); + testDoesNothing(sup, [{ text: 'bgin', type: '' }], '3', 2); + testDoesNothing(sup, [{ text: 'b3in', type: '' }], 'g', 3); + testDoesNothing(sup, [{ text: 'b3gn', type: '' }], 'i', 4); + testDoesNothing(sup, [{ text: 'b3gi', type: '' }], 'n', 5); - testDoesNothing(sup, [{ text: 'begin', type: 'string' }], 4); + testDoesNothing(sup, [{ text: 'begi', type: 'string' }], 'n', 5); - testAppends(sup, [{ text: '"', type: 'string' }, { text: 'begin', type: '' }], 5, 'end'); - testDoesNothing(sup, [{ text: '"', type: 'string' }, { text: 'begin', type: 'string' }], 5); + testAppends(sup, [{ text: '"', type: 'string' }, { text: 'begi', type: '' }], 'n', 6, 'end'); + testDoesNothing(sup, [{ text: '"', type: 'string' }, { text: 'begi', type: 'string' }], 'n', 6); - testAppends(sup, [{ text: '/**', type: 'string' }], 2, ' */'); + testAppends(sup, [{ text: '/*', type: 'string' }], '*', 3, ' */'); - testDoesNothing(sup, [{ text: 'begin', type: '' }, { text: 'end', type: '' }], 4); + testDoesNothing(sup, [{ text: 'begi', type: '' }, { text: 'end', type: '' }], 'n', 5); }); test('matchOpenBracket', () => { @@ -117,12 +114,12 @@ suite('Editor Modes - Auto Indentation', () => { { docComment: { open: '/**', close: ' */' } } ); - testDoesNothing(sup, [{ text: '\t\t{', type: '' }], 0); - testDoesNothing(sup, [{ text: '\t\t{', type: '' }], 1); - testDoesNothing(sup, [{ text: '\t\t{', type: '' }], 2); + testDoesNothing(sup, [{ text: '\t{', type: '' }], '\t', 1); + testDoesNothing(sup, [{ text: '\t{', type: '' }], '\t', 2); + testDoesNothing(sup, [{ text: '\t\t', type: '' }], '{', 3); - testDoesNothing(sup, [{ text: '\t\t}', type: '' }], 0); - testDoesNothing(sup, [{ text: '\t\t}', type: '' }], 1); - testMatchBracket(sup, [{ text: '\t\t}', type: '' }], 2, '}'); + testDoesNothing(sup, [{ text: '\t}', type: '' }], '\t', 1); + testDoesNothing(sup, [{ text: '\t}', type: '' }], '\t', 2); + testMatchBracket(sup, [{ text: '\t\t', type: '' }], '}', 3, '}'); }); }); diff --git a/src/vs/editor/test/common/viewLayout/viewLineParts.test.ts b/src/vs/editor/test/common/viewLayout/viewLineParts.test.ts index 0a16e241864..b77ad0d1f5b 100644 --- a/src/vs/editor/test/common/viewLayout/viewLineParts.test.ts +++ b/src/vs/editor/test/common/viewLayout/viewLineParts.test.ts @@ -35,13 +35,13 @@ suite('Editor ViewLayout - ViewLineParts', () => { test('issue #3462: no whitespace shown at the end of a decorated line', () => { var result = LineDecorationsNormalizer.normalize(3, 1, [ - newDecoration(3, 15, 3, 21, 'trailing whitespace'), + newDecoration(3, 15, 3, 21, 'vs-whitespace'), newDecoration(3, 20, 3, 21, 'inline-folded'), ]); assert.deepEqual(result, [ - new DecorationSegment(14, 18, 'trailing whitespace'), - new DecorationSegment(19, 19, 'trailing whitespace inline-folded') + new DecorationSegment(14, 18, 'vs-whitespace'), + new DecorationSegment(19, 19, 'vs-whitespace inline-folded') ]); }); @@ -102,10 +102,10 @@ suite('Editor ViewLayout - ViewLineParts', () => { 0, 'boundary', [ - new ViewLineToken(0, ' leading whitespace'), + new ViewLineToken(0, ' vs-whitespace'), new ViewLineToken(4, 'a'), new ViewLineToken(6, 'b'), - new ViewLineToken(16, 'b trailing whitespace') + new ViewLineToken(16, 'b vs-whitespace') ] ); }); @@ -120,12 +120,12 @@ suite('Editor ViewLayout - ViewLineParts', () => { 0, 'boundary', [ - new ViewLineToken(0, ' leading whitespace'), - new ViewLineToken(4, ' leading whitespace'), + new ViewLineToken(0, ' vs-whitespace'), + new ViewLineToken(4, ' vs-whitespace'), new ViewLineToken(8, 'a'), new ViewLineToken(10, 'b'), - new ViewLineToken(20, 'b trailing whitespace'), - new ViewLineToken(24, 'b trailing whitespace'), + new ViewLineToken(20, 'b vs-whitespace'), + new ViewLineToken(24, 'b vs-whitespace'), ] ); }); @@ -140,11 +140,11 @@ suite('Editor ViewLayout - ViewLineParts', () => { 0, 'boundary', [ - new ViewLineToken(0, ' leading whitespace'), - new ViewLineToken(1, ' leading whitespace'), + new ViewLineToken(0, ' vs-whitespace'), + new ViewLineToken(1, ' vs-whitespace'), new ViewLineToken(2, 'a'), new ViewLineToken(4, 'b'), - new ViewLineToken(14, 'b trailing whitespace'), + new ViewLineToken(14, 'b vs-whitespace'), ] ); }); @@ -159,15 +159,15 @@ suite('Editor ViewLayout - ViewLineParts', () => { 0, 'boundary', [ - new ViewLineToken(0, ' leading whitespace'), - new ViewLineToken(3, ' leading whitespace'), - new ViewLineToken(4, ' leading whitespace'), + new ViewLineToken(0, ' vs-whitespace'), + new ViewLineToken(3, ' vs-whitespace'), + new ViewLineToken(4, ' vs-whitespace'), new ViewLineToken(6, 'a'), new ViewLineToken(8, 'b'), - new ViewLineToken(18, 'b trailing whitespace'), - new ViewLineToken(20, 'b trailing whitespace'), - new ViewLineToken(23, 'b trailing whitespace'), - new ViewLineToken(27, 'b trailing whitespace'), + new ViewLineToken(18, 'b vs-whitespace'), + new ViewLineToken(20, 'b vs-whitespace'), + new ViewLineToken(23, 'b vs-whitespace'), + new ViewLineToken(27, 'b vs-whitespace'), ] ); }); @@ -182,15 +182,15 @@ suite('Editor ViewLayout - ViewLineParts', () => { 0, 'boundary', [ - new ViewLineToken(0, ' leading whitespace'), - new ViewLineToken(3, ' leading whitespace'), - new ViewLineToken(4, ' leading whitespace'), + new ViewLineToken(0, ' vs-whitespace'), + new ViewLineToken(3, ' vs-whitespace'), + new ViewLineToken(4, ' vs-whitespace'), new ViewLineToken(6, 'a'), new ViewLineToken(8, 'b'), - new ViewLineToken(18, 'b trailing whitespace'), - new ViewLineToken(20, 'b trailing whitespace'), - new ViewLineToken(23, 'b trailing whitespace'), - new ViewLineToken(27, 'b trailing whitespace'), + new ViewLineToken(18, 'b vs-whitespace'), + new ViewLineToken(20, 'b vs-whitespace'), + new ViewLineToken(23, 'b vs-whitespace'), + new ViewLineToken(27, 'b vs-whitespace'), ] ); }); @@ -207,13 +207,13 @@ suite('Editor ViewLayout - ViewLineParts', () => { 'boundary', [ new ViewLineToken(0, ''), - new ViewLineToken(2, ' leading whitespace'), + new ViewLineToken(2, ' vs-whitespace'), new ViewLineToken(4, 'a'), new ViewLineToken(6, 'b'), - new ViewLineToken(16, 'b trailing whitespace'), - new ViewLineToken(18, 'b trailing whitespace'), - new ViewLineToken(21, 'b trailing whitespace'), - new ViewLineToken(25, 'b trailing whitespace'), + new ViewLineToken(16, 'b vs-whitespace'), + new ViewLineToken(18, 'b vs-whitespace'), + new ViewLineToken(21, 'b vs-whitespace'), + new ViewLineToken(25, 'b vs-whitespace'), ] ); }); @@ -230,11 +230,11 @@ suite('Editor ViewLayout - ViewLineParts', () => { 'boundary', [ new ViewLineToken(0, ''), - new ViewLineToken(2, ' embedded whitespace'), + new ViewLineToken(2, ' vs-whitespace'), new ViewLineToken(4, ''), new ViewLineToken(6, 'a'), new ViewLineToken(7, 'b'), - new ViewLineToken(9, 'b embedded whitespace'), + new ViewLineToken(9, 'b vs-whitespace'), new ViewLineToken(11, 'b'), ] ); @@ -251,12 +251,12 @@ suite('Editor ViewLayout - ViewLineParts', () => { 0, 'all', [ - new ViewLineToken(0, ' leading whitespace'), + new ViewLineToken(0, ' vs-whitespace'), new ViewLineToken(1, ''), new ViewLineToken(4, 'a'), - new ViewLineToken(6, 'b embedded whitespace'), + new ViewLineToken(6, 'b vs-whitespace'), new ViewLineToken(7, 'b'), - new ViewLineToken(13, 'b trailing whitespace'), + new ViewLineToken(13, 'b vs-whitespace'), ] ); }); @@ -397,7 +397,7 @@ suite('Editor ViewLayout - ViewLineParts', () => { '\t', 6, [ - new ViewLineToken(0, 'leading whitespace') + new ViewLineToken(0, 'vs-whitespace') ] ); testGetColumnOfLinePartOffset(0, 6, 0, 1); diff --git a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts index d720a953fc4..490ee9126f8 100644 --- a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts +++ b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts @@ -139,7 +139,7 @@ suite('viewLineRenderer.renderLine', () => { test('typical line', () => { let lineText = '\t export class Game { // http://test.com '; let lineParts = [ - createPart(0, 'block meta ts leading whitespace'), + createPart(0, 'block meta ts vs-whitespace'), createPart(5, 'block declaration meta modifier object storage ts'), createPart(11, 'block declaration meta object ts'), createPart(12, 'block declaration meta object storage type ts'), @@ -150,10 +150,10 @@ suite('viewLineRenderer.renderLine', () => { createPart(24, 'block body declaration meta object ts'), createPart(25, 'block body comment declaration line meta object ts'), createPart(28, 'block body comment declaration line meta object ts detected-link'), - createPart(43, 'block body comment declaration line meta object ts trailing whitespace'), + createPart(43, 'block body comment declaration line meta object ts vs-whitespace'), ]; let expectedOutput = [ - '→   ····', + '→   ····', 'export', ' ', 'class', @@ -164,7 +164,7 @@ suite('viewLineRenderer.renderLine', () => { ' ', '// ', 'http://test.com', - '·····' + '·····' ].join(''); let expectedOffsetsArr = [ [0, 4, 5, 6, 7], diff --git a/src/vs/platform/configuration/common/configuration.ts b/src/vs/platform/configuration/common/configuration.ts index bb9da7f2314..079da565997 100644 --- a/src/vs/platform/configuration/common/configuration.ts +++ b/src/vs/platform/configuration/common/configuration.ts @@ -24,6 +24,12 @@ export interface IConfigurationService { */ lookup(key: string): IConfigurationValue; + /** + * Returns the defined keys of configurations in the different scopes + * the key is defined. + */ + keys(): IConfigurationKeys; + /** * Similar to #getConfiguration() but ensures that the latest configuration * from disk is fetched. @@ -46,6 +52,11 @@ export interface IConfigurationValue { user: T; } +export interface IConfigurationKeys { + default: string[]; + user: string[]; +} + /** * A helper function to get the configuration value with a specific settings path (e.g. config.some.setting) */ @@ -54,7 +65,7 @@ export function getConfigurationValue(config: any, settingPath: string, defau let current = config; for (let i = 0; i < path.length; i++) { current = current[path[i]]; - if (!current) { + if (typeof current === 'undefined') { return undefined; } } @@ -65,4 +76,4 @@ export function getConfigurationValue(config: any, settingPath: string, defau const result = accessSetting(config, path); return typeof result === 'undefined' ? defaultValue : result; -} \ No newline at end of file +} diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index a0254f8aa61..8de35b3268b 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -6,12 +6,12 @@ import { TPromise } from 'vs/base/common/winjs.base'; import * as objects from 'vs/base/common/objects'; -import { getDefaultValues, flatten } from 'vs/platform/configuration/common/model'; +import { getDefaultValues, flatten, getConfigurationKeys } from 'vs/platform/configuration/common/model'; import { ConfigWatcher } from 'vs/base/node/config'; import { Registry } from 'vs/platform/platform'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, getConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationServiceEvent, IConfigurationValue, getConfigurationValue, IConfigurationKeys } from 'vs/platform/configuration/common/configuration'; import Event, { Emitter } from 'vs/base/common/event'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -89,6 +89,13 @@ export class ConfigurationService implements IConfigurationService, IDisposab }; } + public keys(): IConfigurationKeys { + return { + default: getConfigurationKeys(), + user: Object.keys(this.rawConfig.getConfig()) + }; + } + private getConsolidatedConfig(): T { const defaults = getDefaultValues(); // defaults coming from contributions to registries const user = flatten(this.rawConfig.getConfig()); // user configured settings diff --git a/src/vs/platform/configuration/test/common/testConfigurationService.ts b/src/vs/platform/configuration/test/common/testConfigurationService.ts index 1da6313bcc7..08b31b4c5da 100644 --- a/src/vs/platform/configuration/test/common/testConfigurationService.ts +++ b/src/vs/platform/configuration/test/common/testConfigurationService.ts @@ -8,7 +8,8 @@ import 'vs/workbench/parts/files/browser/files.contribution'; // load our contribution into the test import { TPromise } from 'vs/base/common/winjs.base'; import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { IConfigurationService, getConfigurationValue, IConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { getConfigurationKeys } from 'vs/platform/configuration/common/model'; +import { IConfigurationService, getConfigurationValue, IConfigurationValue, IConfigurationKeys } from 'vs/platform/configuration/common/configuration'; export class TestConfigurationService extends EventEmitter implements IConfigurationService { public _serviceBrand: any; @@ -39,4 +40,11 @@ export class TestConfigurationService extends EventEmitter implements IConfigura user: getConfigurationValue(this.getConfiguration(), key) }; } + + public keys(): IConfigurationKeys { + return { + default: getConfigurationKeys(), + user: Object.keys(this.configuration) + }; + } } diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index 2bebb45e399..fd2de5827bf 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -20,11 +20,6 @@ export interface IEditorService { * Specific overload to open an instance of IResourceInput. */ openEditor(input: IResourceInput, sideBySide?: boolean): TPromise; - - /** - * Specific overload to resolve a IResourceInput to an editor model with a text representation. - */ - resolveEditorModel(input: IResourceInput, refresh?: boolean): TPromise; } export interface IEditorModel { diff --git a/src/vs/platform/environment/common/http.ts b/src/vs/platform/environment/common/http.ts new file mode 100644 index 00000000000..d1bf7af0181 --- /dev/null +++ b/src/vs/platform/environment/common/http.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +import { TPromise } from 'vs/base/common/winjs.base'; +import { getMachineId } from 'vs/base/node/id'; +import pkg from 'vs/platform/package'; + +export function getCommonHTTPHeaders(): TPromise<{ [key: string]: string; }> { + return getMachineId().then(machineId => ({ + 'X-Market-Client-Id': `VSCode ${pkg.version}`, + 'User-Agent': `VSCode ${pkg.version}`, + 'X-Market-User-Id': machineId + })); +} \ No newline at end of file diff --git a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts index c5969b330cb..42207bc9ae7 100644 --- a/src/vs/platform/extensionManagement/common/extensionEnablementService.ts +++ b/src/vs/platform/extensionManagement/common/extensionEnablementService.ts @@ -11,7 +11,6 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IWorkspaceContextService, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IMessageService } from 'vs/platform/message/common/message'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensions/disabled'; @@ -20,7 +19,6 @@ export class ExtensionEnablementService implements IExtensionEnablementService { _serviceBrand: any; - private workspace: IWorkspace; private disposables: IDisposable[] = []; private _onEnablementChanged = new Emitter(); @@ -28,25 +26,36 @@ export class ExtensionEnablementService implements IExtensionEnablementService { constructor( @IStorageService private storageService: IStorageService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IMessageService private messageService: IMessageService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, @IEnvironmentService private environmentService: IEnvironmentService, @IExtensionManagementService private extensionManagementService: IExtensionManagementService ) { - this.workspace = contextService.getWorkspace(); extensionManagementService.onDidUninstallExtension(this.onDidUninstallExtension, this, this.disposables); } + private get workspace(): IWorkspace { + return this.contextService.getWorkspace(); + } + public getGloballyDisabledExtensions(): string[] { - return this.getDisabledExtensionsFromStorage(StorageScope.GLOBAL); + return this.getDisabledExtensions(StorageScope.GLOBAL); } public getWorkspaceDisabledExtensions(): string[] { - return this.getDisabledExtensionsFromStorage(StorageScope.WORKSPACE); + return this.getDisabledExtensions(StorageScope.WORKSPACE); } public canEnable(identifier: string): boolean { - return !this.environmentService.disableExtensions && this.isDisabled(identifier); + if (this.environmentService.disableExtensions) { + return false; + } + if (this.getGloballyDisabledExtensions().indexOf(identifier) !== -1) { + return true; + } + if (this.getWorkspaceDisabledExtensions().indexOf(identifier) !== -1) { + return true; + } + return false; } public setEnablement(identifier: string, enable: boolean, workspace: boolean = false): TPromise { @@ -58,70 +67,52 @@ export class ExtensionEnablementService implements IExtensionEnablementService { return TPromise.wrap(false); } - if (this.isDisabled(identifier) === !enable) { - return TPromise.wrap(false); - } - if (enable) { if (workspace) { - this.enableExtension(identifier, StorageScope.WORKSPACE); + return this.enableExtension(identifier, StorageScope.WORKSPACE); } else { - this.enableExtension(identifier, StorageScope.GLOBAL); + return this.enableExtension(identifier, StorageScope.GLOBAL); } } else { if (workspace) { - this.disableExtension(identifier, StorageScope.WORKSPACE); + return this.disableExtension(identifier, StorageScope.WORKSPACE); } else { - this.disableExtension(identifier, StorageScope.GLOBAL); + return this.disableExtension(identifier, StorageScope.GLOBAL); } } - - return TPromise.wrap(true); - } - - private getDisabledExtensions(): string[] { - const globalDisabledExtensions = this.getGloballyDisabledExtensions(); - const workspaceDisabledExtensions = this.getWorkspaceDisabledExtensions(); - return distinct([...workspaceDisabledExtensions, ...globalDisabledExtensions]); - } - - private isDisabled(identifier: string): boolean { - return this.getDisabledExtensions().indexOf(identifier) !== -1; - } - - private getDisabledExtensionsFromStorage(scope?: StorageScope): string[] { - if (scope !== void 0) { - return this._getDisabledExtensions(scope); - } - - const globallyDisabled = this._getDisabledExtensions(StorageScope.GLOBAL); - const workspaceDisabled = this._getDisabledExtensions(StorageScope.WORKSPACE); - return [...globallyDisabled, ...workspaceDisabled]; } private disableExtension(identifier: string, scope: StorageScope): TPromise { - let disabledExtensions = this._getDisabledExtensions(scope); - disabledExtensions.push(identifier); - this._setDisabledExtensions(disabledExtensions, scope, identifier); - return TPromise.wrap(true); + let disabledExtensions = this.getDisabledExtensions(scope); + const index = disabledExtensions.indexOf(identifier); + if (index === -1) { + disabledExtensions.push(identifier); + this.setDisabledExtensions(disabledExtensions, scope, identifier); + return TPromise.wrap(true); + } + return TPromise.wrap(false); } private enableExtension(identifier: string, scope: StorageScope): TPromise { - let disabledExtensions = this._getDisabledExtensions(scope); + let disabledExtensions = this.getDisabledExtensions(scope); const index = disabledExtensions.indexOf(identifier); if (index !== -1) { disabledExtensions.splice(index, 1); - this._setDisabledExtensions(disabledExtensions, scope, identifier); + this.setDisabledExtensions(disabledExtensions, scope, identifier); + return TPromise.wrap(true); } - return TPromise.wrap(true); + return TPromise.wrap(false); } - private _getDisabledExtensions(scope: StorageScope): string[] { + private getDisabledExtensions(scope: StorageScope): string[] { + if (scope === StorageScope.WORKSPACE && !this.workspace) { + return []; + } const value = this.storageService.get(DISABLED_EXTENSIONS_STORAGE_PATH, scope, ''); return value ? distinct(value.split(',')) : []; } - private _setDisabledExtensions(disabledExtensions: string[], scope: StorageScope, extension: string): void { + private setDisabledExtensions(disabledExtensions: string[], scope: StorageScope, extension: string): void { if (disabledExtensions.length) { this.storageService.store(DISABLED_EXTENSIONS_STORAGE_PATH, disabledExtensions.join(','), scope); } else { diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index b31ffe53d0d..a3bc9eab7de 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -23,7 +23,7 @@ import pkg from 'vs/platform/package'; import product from 'vs/platform/product'; import { isVersionValid } from 'vs/platform/extensions/node/extensionValidator'; import * as url from 'url'; -import { getMachineId } from 'vs/base/node/id'; +import { getCommonHTTPHeaders } from 'vs/platform/environment/common/http'; interface IRawGalleryExtensionFile { assetType: string; @@ -262,12 +262,8 @@ export class ExtensionGalleryService implements IExtensionGalleryService { private extensionsGalleryUrl: string; @memoize - private get commonHeaders(): TPromise<{ [key: string]: string; }> { - return getMachineId().then(machineId => ({ - 'X-Market-Client-Id': `VSCode ${pkg.version}`, - 'User-Agent': `VSCode ${pkg.version}`, - 'X-Market-User-Id': machineId - })); + private get commonHTTPHeaders(): TPromise<{ [key: string]: string; }> { + return getCommonHTTPHeaders(); } constructor( @@ -288,7 +284,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } getRequestHeaders(): TPromise<{ [key: string]: string; }> { - return this.commonHeaders; + return this.commonHTTPHeaders; } query(options: IQueryOptions = {}): TPromise> { @@ -338,7 +334,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { } private queryGallery(query: Query): TPromise<{ galleryExtensions: IRawGalleryExtension[], total: number; }> { - return this.commonHeaders + return this.commonHTTPHeaders .then(headers => { const data = JSON.stringify(query.raw); @@ -478,7 +474,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { parsedUrl.search = undefined; parsedUrl.query['redirect'] = 'true'; - return this.commonHeaders.then(headers => { + return this.commonHTTPHeaders.then(headers => { headers = assign({}, headers, options.headers || {}); options = assign({}, options, { headers }); diff --git a/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts b/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts new file mode 100644 index 00000000000..332ee704991 --- /dev/null +++ b/src/vs/platform/extensionManagement/test/common/extensionEnablementService.test.ts @@ -0,0 +1,274 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as sinon from 'sinon'; +import * as assert from 'assert'; +import { IExtensionManagementService, IExtensionEnablementService, DidUninstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; +import { TestInstantiationService } from 'vs/test/utils/instantiationTestUtils'; +import { TestEnvironmentService, TestWorkspace } from 'vs/test/utils/servicesTestUtils'; +import { Emitter } from 'vs/base/common/event'; +import { StorageService, InMemoryLocalStorage } from 'vs/workbench/services/storage/common/storageService'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { IWorkspaceContextService, WorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; + +function storageService(instantiationService: TestInstantiationService): IStorageService { + let service = instantiationService.get(IStorageService); + if (!service) { + let workspaceContextService = instantiationService.get(IWorkspaceContextService); + if (!workspaceContextService) { + workspaceContextService = instantiationService.stub(IWorkspaceContextService, WorkspaceContextService); + instantiationService.stub(IWorkspaceContextService, 'getWorkspace', TestWorkspace); + } + service = instantiationService.stub(IStorageService, instantiationService.createInstance(StorageService, new InMemoryLocalStorage(), new InMemoryLocalStorage())); + } + return service; +} + +export class TestExtensionEnablementService extends ExtensionEnablementService { + constructor(instantiationService: TestInstantiationService) { + super(storageService(instantiationService), instantiationService.get(IWorkspaceContextService), + instantiationService.get(IEnvironmentService) || instantiationService.stub(IEnvironmentService, TestEnvironmentService), + instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: new Emitter() })); + } + + public reset(): void { + this.getGloballyDisabledExtensions().forEach(d => this.setEnablement(d, true)); + this.getWorkspaceDisabledExtensions().forEach(d => this.setEnablement(d, true, true)); + } +} + +suite('ExtensionEnablementService Test', () => { + + let instantiationService: TestInstantiationService; + let testObject: IExtensionEnablementService; + + const didUninstallEvent: Emitter = new Emitter(); + + setup(() => { + instantiationService = new TestInstantiationService(); + instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, }); + testObject = new TestExtensionEnablementService(instantiationService); + }); + + teardown(() => { + (testObject).dispose(); + }); + + test('test when no extensions are disabled globally', () => { + assert.deepEqual([], testObject.getGloballyDisabledExtensions()); + }); + + test('test when no extensions are disabled for workspace', () => { + assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); + }); + + test('test when no extensions are disabled for workspace when there is no workspace', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => { + instantiationService.stub(IWorkspaceContextService, 'getWorkspace', null); + assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); + }) + .then(done, done); + }); + + test('test disable an extension globally', (done) => { + testObject.setEnablement('pub.a', false) + .then(() => assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions())) + .then(done, done); + }); + + test('test disable an extension globally should return truthy promise', (done) => { + testObject.setEnablement('pub.a', false) + .then(value => assert.ok(value)) + .then(done, done); + }); + + test('test disable an extension globally triggers the change event', (done) => { + const target = sinon.spy(); + testObject.onEnablementChanged(target); + testObject.setEnablement('pub.a', false) + .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(done, done); + }); + + test('test disable an extension globally again should return a falsy promise', (done) => { + testObject.setEnablement('pub.a', false) + .then(() => testObject.setEnablement('pub.a', false)) + .then(value => assert.ok(!value)) + .then(done, done); + }); + + test('test disable an extension for workspace', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions())) + .then(done, done); + }); + + test('test disable an extension for workspace returns a truthy promise', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(value => assert.ok(value)) + .then(done, done); + }); + + test('test disable an extension for workspace again should return a falsy promise', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.setEnablement('pub.a', false, true)) + .then(value => assert.ok(!value)) + .then(done, done); + }); + + test('test disable an extension for workspace and then globally', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.setEnablement('pub.a', false)) + .then(() => { + assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + }) + .then(done, done); + }); + + test('test disable an extension for workspace and then globally return a truthy promise', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.setEnablement('pub.a', false)) + .then(value => assert.ok(value)) + .then(done, done); + }); + + test('test disable an extension for workspace and then globally triggers the change event', (done) => { + const target = sinon.spy(); + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.onEnablementChanged(target)) + .then(() => testObject.setEnablement('pub.a', false)) + .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(done, done); + }); + + test('test disable an extension globally and then for workspace', (done) => { + testObject.setEnablement('pub.a', false) + .then(() => testObject.setEnablement('pub.a', false, true)) + .then(() => { + assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + }) + .then(done, done); + }); + + test('test disable an extension globally and then for workspace return a truthy promise', (done) => { + testObject.setEnablement('pub.a', false) + .then(() => testObject.setEnablement('pub.a', false, true)) + .then(value => assert.ok(value)) + .then(done, done); + }); + + test('test disable an extension globally and then for workspace triggers the change event', (done) => { + const target = sinon.spy(); + testObject.setEnablement('pub.a', false) + .then(() => testObject.onEnablementChanged(target)) + .then(() => testObject.setEnablement('pub.a', false, true)) + .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(done, done); + }); + + test('test disable an extension for workspace when there is no workspace throws error', (done) => { + instantiationService.stub(IWorkspaceContextService, 'getWorkspace', null); + testObject.setEnablement('pub.a', false, true) + .then(() => assert.fail('should throw an error'), error => assert.ok(error)) + .then(done, done); + }); + + test('test enable an extension globally', (done) => { + testObject.setEnablement('pub.a', false) + .then(() => testObject.setEnablement('pub.a', true)) + .then(() => assert.deepEqual([], testObject.getGloballyDisabledExtensions())) + .then(done, done); + }); + + test('test enable an extension globally return truthy promise', (done) => { + testObject.setEnablement('pub.a', false) + .then(() => testObject.setEnablement('pub.a', true)) + .then(value => assert.ok(value)) + .then(done, done); + }); + + test('test enable an extension globally triggers change event', (done) => { + const target = sinon.spy(); + testObject.setEnablement('pub.a', false) + .then(() => testObject.onEnablementChanged(target)) + .then(() => testObject.setEnablement('pub.a', true)) + .then(() => assert.ok(target.calledWithExactly('pub.a'))) + .then(done, done); + }); + + test('test enable an extension globally when already enabled return falsy promise', (done) => { + testObject.setEnablement('pub.a', true) + .then(value => assert.ok(!value)) + .then(done, done); + }); + + test('test enable an extension for workspace', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.setEnablement('pub.a', true, true)) + .then(() => assert.deepEqual([], testObject.getWorkspaceDisabledExtensions())) + .then(done, done); + }); + + test('test enable an extension for workspace return truthy promise', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.setEnablement('pub.a', true, true)) + .then(value => assert.ok(value)) + .then(done, done); + }); + + test('test enable an extension for workspace triggers change event', (done) => { + const target = sinon.spy(); + testObject.setEnablement('pub.b', false, true) + .then(() => testObject.onEnablementChanged(target)) + .then(() => testObject.setEnablement('pub.b', true, true)) + .then(() => assert.ok(target.calledWithExactly('pub.b'))) + .then(done, done); + }); + + test('test enable an extension for workspace when already enabled return falsy promise', (done) => { + testObject.setEnablement('pub.a', true, true) + .then(value => assert.ok(!value)) + .then(done, done); + }); + + test('test enable an extension for workspace when disabled in workspace and gloablly', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.setEnablement('pub.a', false)) + .then(() => testObject.setEnablement('pub.a', true, true)) + .then(() => { + assert.deepEqual(['pub.a'], testObject.getGloballyDisabledExtensions()); + assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); + }) + .then(done, done); + }); + + test('test enable an extension globally when disabled in workspace and gloablly', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.setEnablement('pub.a', false)) + .then(() => testObject.setEnablement('pub.a', true)) + .then(() => { + assert.deepEqual(['pub.a'], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([], testObject.getGloballyDisabledExtensions()); + }) + .then(done, done); + }); + + test('test remove an extension from disablement list when uninstalled', (done) => { + testObject.setEnablement('pub.a', false, true) + .then(() => testObject.setEnablement('pub.a', false)) + .then(() => didUninstallEvent.fire({ id: 'pub.a' })) + .then(() => { + assert.deepEqual([], testObject.getWorkspaceDisabledExtensions()); + assert.deepEqual([], testObject.getGloballyDisabledExtensions()); + }) + .then(done, done); + }); +}); \ No newline at end of file diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index 119cc706626..defc1db0fc6 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -9,8 +9,6 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionPoint } from 'vs/platform/extensions/common/extensionsRegistry'; -export const ExtensionProperties = ['id', 'name', 'version', 'publisher', 'isBuiltin', 'extensionFolderPath', 'extensionDependencies', 'activationEvents', 'engines', 'main', 'contributes', 'enableProposedApi']; - export interface IExtensionDescription { readonly id: string; readonly name: string; diff --git a/src/vs/platform/opener/test/browser/openerService.test.ts b/src/vs/platform/opener/test/browser/openerService.test.ts index 27b895d91c1..87c0a19dafb 100644 --- a/src/vs/platform/opener/test/browser/openerService.test.ts +++ b/src/vs/platform/opener/test/browser/openerService.test.ts @@ -7,7 +7,7 @@ import URI from 'vs/base/common/uri'; import * as assert from 'assert'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IEditorService, ITextEditorModel, IResourceInput } from 'vs/platform/editor/common/editor'; +import { IEditorService, IResourceInput } from 'vs/platform/editor/common/editor'; import { ICommandService, NullCommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { OpenerService } from 'vs/platform/opener/browser/openerService'; @@ -20,12 +20,8 @@ suite('OpenerService', function () { openEditor(input: IResourceInput): any { lastInput = input; } - resolveEditorModel(): any { - return TPromise.as({}); - } }; - let lastCommand: { id: string, args: any[] }; const commandService = new class implements ICommandService { diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index ee526092e94..b54a41dc3da 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -54,15 +54,16 @@ export class TelemetryService implements ITelemetryService { // #1 `file:///DANGEROUS/PATH/resources/app/Useful/Information` // #2 // Any other file path that doesn't match the approved form above should be cleaned. // #3 "Error: ENOENT; no such file or directory" is often followed with PII, clean it - for (let piiPath of this._piiPaths) { - this._cleanupPatterns.push([new RegExp(escapeRegExpCharacters(piiPath), 'gi'), '']); - } this._cleanupPatterns.push( [/file:\/\/\/.*?\/resources\/app\//gi, ''], [/file:\/\/\/.*/gi, ''], [/ENOENT: no such file or directory.*?\'([^\']+)\'/gi, 'ENOENT: no such file or directory'] ); + for (let piiPath of this._piiPaths) { + this._cleanupPatterns.push([new RegExp(escapeRegExpCharacters(piiPath), 'gi'), '']); + } + if (this._configurationService) { this._updateUserOptIn(); this._configurationService.onDidUpdateConfiguration(this._updateUserOptIn, this, this._disposables); diff --git a/src/vs/platform/telemetry/test/node/telemetryService.test.ts b/src/vs/platform/telemetry/test/node/telemetryService.test.ts index 855369db0ad..947da678a0f 100644 --- a/src/vs/platform/telemetry/test/node/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/node/telemetryService.test.ts @@ -433,6 +433,68 @@ suite('TelemetryService', () => { service.dispose(); })); + test('Unexpected Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinon.test(function () { + + let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); + Errors.setUnexpectedErrorHandler(() => { }); + + try { + let settings = new ErrorTestingSettings(); + let testAppender = new TestTelemetryAppender(); + let service = new TelemetryService({ appender: testAppender, piiPaths: [ settings.personalInfo + '/resources/app/' ] }, undefined); + const errorTelemetry = new ErrorTelemetry(service); + + let dangerousPathWithImportantInfoError: any = new Error(settings.dangerousPathWithImportantInfo); + dangerousPathWithImportantInfoError.stack = settings.stack; + + // Test that important information remains but personal info does not + Errors.onUnexpectedError(dangerousPathWithImportantInfoError); + this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); + + assert.notEqual(testAppender.events[0].data.message.indexOf(settings.importantInfo), -1); + assert.equal(testAppender.events[0].data.message.indexOf(settings.personalInfo), -1); + assert.equal(testAppender.events[0].data.message.indexOf(settings.filePrefix), -1); + assert.notEqual(testAppender.events[0].data.stack.indexOf(settings.importantInfo), -1); + assert.equal(testAppender.events[0].data.stack.indexOf(settings.personalInfo), -1); + assert.equal(testAppender.events[0].data.stack.indexOf(settings.filePrefix), -1); + assert.notEqual(testAppender.events[0].data.stack.indexOf(settings.stack[4]), -1); + assert.equal(testAppender.events[0].data.stack.split('\n').length, settings.stack.length); + + errorTelemetry.dispose(); + service.dispose(); + } + finally { + Errors.setUnexpectedErrorHandler(origErrorHandler); + } + })); + + test('Uncaught Error Telemetry removes PII but preserves Code file path when PIIPath is configured', sinon.test(function () { + let errorStub = this.stub(window, 'onerror'); + let settings = new ErrorTestingSettings(); + let testAppender = new TestTelemetryAppender(); + let service = new TelemetryService({ appender: testAppender, piiPaths: [ settings.personalInfo + '/resources/app/' ] }, undefined); + const errorTelemetry = new ErrorTelemetry(service); + + let dangerousPathWithImportantInfoError: any = new Error('dangerousPathWithImportantInfo'); + dangerousPathWithImportantInfoError.stack = settings.stack; + (window.onerror)(settings.dangerousPathWithImportantInfo, 'test.js', 2, 42, dangerousPathWithImportantInfoError); + this.clock.tick(ErrorTelemetry.ERROR_FLUSH_TIMEOUT); + + assert.equal(errorStub.callCount, 1); + // Test that important information remains but personal info does not + assert.notEqual(testAppender.events[0].data.message.indexOf(settings.importantInfo), -1); + assert.equal(testAppender.events[0].data.message.indexOf(settings.personalInfo), -1); + assert.equal(testAppender.events[0].data.message.indexOf(settings.filePrefix), -1); + assert.notEqual(testAppender.events[0].data.stack.indexOf(settings.importantInfo), -1); + assert.equal(testAppender.events[0].data.stack.indexOf(settings.personalInfo), -1); + assert.equal(testAppender.events[0].data.stack.indexOf(settings.filePrefix), -1); + assert.notEqual(testAppender.events[0].data.stack.indexOf(settings.stack[4]), -1); + assert.equal(testAppender.events[0].data.stack.split('\n').length, settings.stack.length); + + errorTelemetry.dispose(); + service.dispose(); + })); + test('Unexpected Error Telemetry removes PII but preserves Missing Model error message', sinon.test(function () { let origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler(); @@ -627,6 +689,7 @@ suite('TelemetryService', () => { user: getConfigurationValue(this.getConfiguration(), key) }; }, + keys() { return { default: [], user: [] }; }, onDidUpdateConfiguration: emitter.event }); diff --git a/src/vs/platform/textmodelResolver/common/resolver.ts b/src/vs/platform/textmodelResolver/common/resolver.ts new file mode 100644 index 00000000000..e0275e77c9a --- /dev/null +++ b/src/vs/platform/textmodelResolver/common/resolver.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { TPromise } from 'vs/base/common/winjs.base'; +import URI from 'vs/base/common/uri'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IModel } from 'vs/editor/common/editorCommon'; +import { ITextEditorModel } from 'vs/platform/editor/common/editor'; +import { IDisposable } from 'vs/base/common/lifecycle'; + +export const ITextModelResolverService = createDecorator('textModelResolverService'); + +export interface ITextModelResolverService { + _serviceBrand: any; + + /** + * Given a resource, tries to resolve a ITextEditorModel out of it. Will support many schemes like file://, untitled://, + * inMemory:// and for anything else fall back to the model content provider registry. + */ + resolve(resource: URI): TPromise; + + /** + * For unknown resources, allows to register a content provider such as this service is able to resolve arbritrary + * resources to ITextEditorModels. + */ + registerTextModelContentProvider(scheme: string, provider: ITextModelContentProvider): IDisposable; +} + +export interface ITextModelContentProvider { + + /** + * Given a resource, return the content of the resource as IModel. + */ + provideTextContent(resource: URI): TPromise; +} \ No newline at end of file diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 9e81bbfecca..5281dfa4599 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -18,6 +18,34 @@ export interface IWindowsService { openFilePicker(windowId: number, forceNewWindow?: boolean, path?: string): TPromise; openFolderPicker(windowId: number, forceNewWindow?: boolean): TPromise; reloadWindow(windowId: number): TPromise; + openDevTools(windowId: number): TPromise; + toggleDevTools(windowId: number): TPromise; + // TODO@joao: rename, shouldn't this be closeWindow? + closeFolder(windowId: number): TPromise; + toggleFullScreen(windowId: number): TPromise; + setRepresentedFilename(windowId: number, fileName: string): TPromise; + getRecentlyOpen(windowId: number): TPromise<{ files: string[]; folders: string[]; }>; + focusWindow(windowId: number): TPromise; + setDocumentEdited(windowId: number, flag: boolean): TPromise; + toggleMenuBar(windowId: number): TPromise; + + // Global methods + // TODO@joao: rename, shouldn't this be openWindow? + windowOpen(paths: string[], forceNewWindow?: boolean): TPromise; + openNewWindow(): TPromise; + showWindow(windowId: number): TPromise; + getWindows(): TPromise<{ id: number; path: string; title: string; }[]>; + log(severity: string, ...messages: string[]): TPromise; + // TODO@joao: what? + closeExtensionHostWindow(extensionDevelopmentPath: string): TPromise; + showItemInFolder(path: string): TPromise; + + // This needs to be handled from browser process to prevent + // foreground ordering issues on Windows + openExternal(url: string): TPromise; + + // TODO: this is a bit backwards + startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise; } export const IWindowService = createDecorator('windowService'); @@ -26,8 +54,18 @@ export interface IWindowService { _serviceBrand: any; + getCurrentWindowId(): number; openFileFolderPicker(forceNewWindow?: boolean): TPromise; openFilePicker(forceNewWindow?: boolean, path?: string): TPromise; openFolderPicker(forceNewWindow?: boolean): TPromise; reloadWindow(): TPromise; + openDevTools(): TPromise; + toggleDevTools(): TPromise; + closeFolder(): TPromise; + toggleFullScreen(): TPromise; + setRepresentedFilename(fileName: string): TPromise; + getRecentlyOpen(): TPromise<{ files: string[]; folders: string[]; }>; + focusWindow(): TPromise; + setDocumentEdited(flag: boolean): TPromise; + toggleMenuBar(): TPromise; } \ No newline at end of file diff --git a/src/vs/platform/windows/common/windowsIpc.ts b/src/vs/platform/windows/common/windowsIpc.ts index a83ac7f6783..4bac80293cb 100644 --- a/src/vs/platform/windows/common/windowsIpc.ts +++ b/src/vs/platform/windows/common/windowsIpc.ts @@ -10,10 +10,27 @@ import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { IWindowsService } from './windows'; export interface IWindowsChannel extends IChannel { - call(command: 'openFileFolderPicker', args: [number, boolean]): TPromise; - call(command: 'openFilePicker', args: [number, boolean, string]): TPromise; - call(command: 'openFolderPicker', args: [number, boolean]): TPromise; + call(command: 'openFileFolderPicker', arg: [number, boolean]): TPromise; + call(command: 'openFilePicker', arg: [number, boolean, string]): TPromise; + call(command: 'openFolderPicker', arg: [number, boolean]): TPromise; call(command: 'reloadWindow', arg: number): TPromise; + call(command: 'toggleDevTools', arg: number): TPromise; + call(command: 'closeFolder', arg: number): TPromise; + call(command: 'toggleFullScreen', arg: number): TPromise; + call(command: 'setRepresentedFilename', arg: [number, string]): TPromise; + call(command: 'getRecentlyOpen', arg: number): TPromise<{ files: string[]; folders: string[]; }>; + call(command: 'focusWindow', arg: number): TPromise; + call(command: 'setDocumentEdited', arg: [number, boolean]): TPromise; + call(command: 'toggleMenuBar', arg: number): TPromise; + call(command: 'windowOpen', arg: [string[], boolean]): TPromise; + call(command: 'openNewWindow'): TPromise; + call(command: 'showWindow', arg: number): TPromise; + call(command: 'getWindows'): TPromise<{ id: number; path: string; title: string; }[]>; + call(command: 'log', arg: [string, string[]]): TPromise; + call(command: 'closeExtensionHostWindow', arg: string): TPromise; + call(command: 'showItemInFolder', arg: string): TPromise; + call(command: 'openExternal', arg: string): TPromise; + call(command: 'startCrashReporter', arg: Electron.CrashReporterStartOptions): TPromise; call(command: string, arg?: any): TPromise; } @@ -27,6 +44,24 @@ export class WindowsChannel implements IWindowsChannel { case 'openFilePicker': return this.service.openFilePicker(arg[0], arg[1], arg[2]); case 'openFolderPicker': return this.service.openFolderPicker(arg[0], arg[1]); case 'reloadWindow': return this.service.reloadWindow(arg); + case 'openDevTools': return this.service.openDevTools(arg); + case 'toggleDevTools': return this.service.toggleDevTools(arg); + case 'closeFolder': return this.service.closeFolder(arg); + case 'toggleFullScreen': return this.service.toggleFullScreen(arg); + case 'setRepresentedFilename': return this.service.setRepresentedFilename(arg[0], arg[1]); + case 'getRecentlyOpen': return this.service.getRecentlyOpen(arg); + case 'focusWindow': return this.service.focusWindow(arg); + case 'setDocumentEdited': return this.service.setDocumentEdited(arg[0], arg[1]); + case 'toggleMenuBar': return this.service.toggleMenuBar(arg); + case 'windowOpen': return this.service.windowOpen(arg[0], arg[1]); + case 'openNewWindow': return this.service.openNewWindow(); + case 'showWindow': return this.service.showWindow(arg); + case 'getWindows': return this.service.getWindows(); + case 'log': return this.service.log(arg[0], arg[1]); + case 'closeExtensionHostWindow': return this.service.closeExtensionHostWindow(arg); + case 'showItemInFolder': return this.service.showItemInFolder(arg); + case 'openExternal': return this.service.openExternal(arg); + case 'startCrashReporter': return this.service.startCrashReporter(arg); } } } @@ -52,4 +87,76 @@ export class WindowsChannelClient implements IWindowsService { reloadWindow(windowId: number): TPromise { return this.channel.call('reloadWindow', windowId); } + + openDevTools(windowId: number): TPromise { + return this.channel.call('openDevTools', windowId); + } + + toggleDevTools(windowId: number): TPromise { + return this.channel.call('toggleDevTools', windowId); + } + + closeFolder(windowId: number): TPromise { + return this.channel.call('closeFolder', windowId); + } + + toggleFullScreen(windowId: number): TPromise { + return this.channel.call('toggleFullScreen', windowId); + } + + setRepresentedFilename(windowId: number, fileName: string): TPromise { + return this.channel.call('setRepresentedFilename', [windowId, fileName]); + } + + getRecentlyOpen(windowId: number): TPromise<{ files: string[]; folders: string[]; }> { + return this.channel.call('getRecentlyOpen', windowId); + } + + focusWindow(windowId: number): TPromise { + return this.channel.call('focusWindow', windowId); + } + + setDocumentEdited(windowId: number, flag: boolean): TPromise { + return this.channel.call('setDocumentEdited', [windowId, flag]); + } + + toggleMenuBar(windowId: number): TPromise { + return this.channel.call('toggleMenuBar', windowId); + } + + windowOpen(paths: string[], forceNewWindow?: boolean): TPromise { + return this.channel.call('windowOpen', [paths, forceNewWindow]); + } + + openNewWindow(): TPromise { + return this.channel.call('openNewWindow'); + } + + showWindow(windowId: number): TPromise { + return this.channel.call('showWindow', windowId); + } + + getWindows(): TPromise<{ id: number; path: string; title: string; }[]> { + return this.channel.call('getWindows'); + } + + log(severity: string, ...messages: string[]): TPromise { + return this.channel.call('log', [severity, messages]); + } + + closeExtensionHostWindow(extensionDevelopmentPath: string): TPromise { + return this.channel.call('closeExtensionHostWindow', extensionDevelopmentPath); + } + + showItemInFolder(path: string): TPromise { + return this.channel.call('showItemInFolder', path); + } + + openExternal(url: string): TPromise { + return this.channel.call('openExternal', url); + } + + startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise { + return this.channel.call('startCrashReporter', config); + } } \ No newline at end of file diff --git a/src/vs/platform/windows/electron-browser/windowService.ts b/src/vs/platform/windows/electron-browser/windowService.ts index aee56786b0e..88b852206f3 100644 --- a/src/vs/platform/windows/electron-browser/windowService.ts +++ b/src/vs/platform/windows/electron-browser/windowService.ts @@ -17,6 +17,10 @@ export class WindowService implements IWindowService { @IWindowsService private windowsService: IWindowsService ) { } + getCurrentWindowId(): number { + return this.windowId; + } + openFileFolderPicker(forceNewWindow?: boolean): TPromise { return this.windowsService.openFileFolderPicker(this.windowId, forceNewWindow); } @@ -32,4 +36,40 @@ export class WindowService implements IWindowService { reloadWindow(): TPromise { return this.windowsService.reloadWindow(this.windowId); } + + openDevTools(): TPromise { + return this.windowsService.openDevTools(this.windowId); + } + + toggleDevTools(): TPromise { + return this.windowsService.toggleDevTools(this.windowId); + } + + closeFolder(): TPromise { + return this.windowsService.closeFolder(this.windowId); + } + + toggleFullScreen(): TPromise { + return this.windowsService.toggleFullScreen(this.windowId); + } + + setRepresentedFilename(fileName: string): TPromise { + return this.windowsService.setRepresentedFilename(this.windowId, fileName); + } + + getRecentlyOpen(): TPromise<{ files: string[]; folders: string[]; }> { + return this.windowsService.getRecentlyOpen(this.windowId); + } + + focusWindow(): TPromise { + return this.windowsService.focusWindow(this.windowId); + } + + setDocumentEdited(flag: boolean): TPromise { + return this.windowsService.setDocumentEdited(this.windowId, flag); + } + + toggleMenuBar(): TPromise { + return this.windowsService.toggleMenuBar(this.windowId); + } } \ No newline at end of file diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index 72407812187..a45b968ae98 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -7,6 +7,8 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { shell, crashReporter } from 'electron'; // TODO@Joao: remove this dependency, move all implementation to this class import { IWindowsMainService } from 'vs/code/electron-main/windows'; @@ -16,7 +18,8 @@ export class WindowsService implements IWindowsService { _serviceBrand: any; constructor( - @IWindowsMainService private windowsMainService: IWindowsMainService + @IWindowsMainService private windowsMainService: IWindowsMainService, + @IEnvironmentService private environmentService: IEnvironmentService ) { } openFileFolderPicker(windowId: number, forceNewWindow?: boolean): TPromise { @@ -43,4 +46,150 @@ export class WindowsService implements IWindowsService { return TPromise.as(null); } + + openDevTools(windowId: number): TPromise { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow) { + vscodeWindow.win.webContents.openDevTools(); + } + + return TPromise.as(null); + } + + toggleDevTools(windowId: number): TPromise { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow) { + vscodeWindow.win.webContents.toggleDevTools(); + } + + return TPromise.as(null); + } + + closeFolder(windowId: number): TPromise { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow) { + this.windowsMainService.open({ cli: this.environmentService.args, forceEmpty: true, windowToUse: vscodeWindow }); + } + + return TPromise.as(null); + } + + toggleFullScreen(windowId: number): TPromise { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow) { + vscodeWindow.toggleFullScreen(); + } + + return TPromise.as(null); + } + + setRepresentedFilename(windowId: number, fileName: string): TPromise { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow) { + vscodeWindow.win.setRepresentedFilename(fileName); + } + + return TPromise.as(null); + } + + getRecentlyOpen(windowId: number): TPromise<{ files: string[]; folders: string[]; }> { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow) { + const { files, folders } = this.windowsMainService.getRecentPathsList(vscodeWindow.config.workspacePath, vscodeWindow.config.filesToOpen); + return TPromise.as({ files, folders }); + } + + return TPromise.as({ files: [], folders: [] }); + } + + focusWindow(windowId: number): TPromise { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow) { + vscodeWindow.win.focus(); + } + + return TPromise.as(null); + } + + setDocumentEdited(windowId: number, flag: boolean): TPromise { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow && vscodeWindow.win.isDocumentEdited() !== flag) { + vscodeWindow.win.setDocumentEdited(flag); + } + + return TPromise.as(null); + } + + toggleMenuBar(windowId: number): TPromise { + this.windowsMainService.toggleMenuBar(windowId); + return TPromise.as(null); + } + + windowOpen(paths: string[], forceNewWindow?: boolean): TPromise { + if (!paths || !paths.length) { + return TPromise.as(null); + } + + this.windowsMainService.open({ cli: this.environmentService.args, pathsToOpen: paths, forceNewWindow: forceNewWindow }); + return TPromise.as(null); + } + + openNewWindow(): TPromise { + this.windowsMainService.openNewWindow(); + return TPromise.as(null); + } + + showWindow(windowId: number): TPromise { + const vscodeWindow = this.windowsMainService.getWindowById(windowId); + + if (vscodeWindow) { + vscodeWindow.win.show(); + } + + return TPromise.as(null); + } + + getWindows(): TPromise<{ id: number; path: string; title: string; }[]> { + const windows = this.windowsMainService.getWindows(); + const result = windows.map(w => ({ path: w.openedWorkspacePath, title: w.win.getTitle(), id: w.id })); + return TPromise.as(result); + } + + log(severity: string, ...messages: string[]): TPromise { + console[severity].apply(console, ...messages); + return TPromise.as(null); + } + + closeExtensionHostWindow(extensionDevelopmentPath: string): TPromise { + const windowOnExtension = this.windowsMainService.findWindow(null, null, extensionDevelopmentPath); + + if (windowOnExtension) { + windowOnExtension.win.close(); + } + + return TPromise.as(null); + } + + showItemInFolder(path: string): TPromise { + shell.showItemInFolder(path); + return TPromise.as(null); + } + + openExternal(url: string): TPromise { + shell.openExternal(url); + return TPromise.as(null); + } + + startCrashReporter(config: Electron.CrashReporterStartOptions): TPromise { + crashReporter.start(config); + return TPromise.as(null); + } } \ No newline at end of file diff --git a/src/vs/test/utils/instantiationTestUtils.ts b/src/vs/test/utils/instantiationTestUtils.ts index 509eec6e6ae..0e34d008c41 100644 --- a/src/vs/test/utils/instantiationTestUtils.ts +++ b/src/vs/test/utils/instantiationTestUtils.ts @@ -54,32 +54,44 @@ export class TestInstantiationService extends InstantiationService { this._servciesMap.set(IKeybindingService, WorkbenchKeybindingService); } + public get(service: ServiceIdentifier): T { + return this._serviceCollection.get(service); + } + + public set(service: ServiceIdentifier, instance: T): T { + return this._serviceCollection.set(service, instance); + } + public mock(service: ServiceIdentifier): T | sinon.SinonMock { return this._create(service, { mock: true }); } public stub(service?: ServiceIdentifier, ctor?: any): T public stub(service?: ServiceIdentifier, obj?: any): T - public stub(service?: ServiceIdentifier, ctor?: any, fnProperty?: string, value?: any): sinon.SinonStub - public stub(service?: ServiceIdentifier, obj?: any, fnProperty?: string, value?: any): sinon.SinonStub - public stub(service?: ServiceIdentifier, fnProperty?: string, value?: any): sinon.SinonStub + public stub(service?: ServiceIdentifier, ctor?: any, property?: string, value?: any): sinon.SinonStub + public stub(service?: ServiceIdentifier, obj?: any, property?: string, value?: any): sinon.SinonStub + public stub(service?: ServiceIdentifier, property?: string, value?: any): sinon.SinonStub public stub(serviceIdentifier?: ServiceIdentifier, arg2?: any, arg3?: string, arg4?: any): sinon.SinonStub { let service = typeof arg2 !== 'string' ? arg2 : void 0; let serviceMock: IServiceMock = { id: serviceIdentifier, service: service }; - let fnProperty = typeof arg2 === 'string' ? arg2 : arg3; + let property = typeof arg2 === 'string' ? arg2 : arg3; let value = typeof arg2 === 'string' ? arg3 : arg4; let stubObject = this._create(serviceMock, { stub: true }); - if (fnProperty) { - if (stubObject[fnProperty].hasOwnProperty('restore')) { - stubObject[fnProperty].restore(); - } - if (typeof value === 'function') { - stubObject[fnProperty] = value; + if (property) { + if (stubObject[property]) { + if (stubObject[property].hasOwnProperty('restore')) { + stubObject[property].restore(); + } + if (typeof value === 'function') { + stubObject[property] = value; + } else { + let stub = value ? sinon.stub().returns(value) : sinon.stub(); + stubObject[property] = stub; + return stub; + } } else { - let stub = value ? sinon.stub().returns(value) : sinon.stub(); - stubObject[fnProperty] = stub; - return stub; + stubObject[property] = value; } } return stubObject; diff --git a/src/vs/test/utils/servicesTestUtils.ts b/src/vs/test/utils/servicesTestUtils.ts index 046f9017d5b..497458e84c7 100644 --- a/src/vs/test/utils/servicesTestUtils.ts +++ b/src/vs/test/utils/servicesTestUtils.ts @@ -22,7 +22,9 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import { IEditorInput, IEditorOptions, IEditorModel, Position, Direction, IEditor, IResourceInput, ITextEditorModel } from 'vs/platform/editor/common/editor'; +import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; +import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceInput } from 'vs/platform/editor/common/editor'; import { IEventService } from 'vs/platform/event/common/event'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IMessageService, IConfirmation } from 'vs/platform/message/common/message'; @@ -114,7 +116,7 @@ export class TestTextFileService extends TextFileService { @IUntitledEditorService untitledEditorService: IUntitledEditorService, @IInstantiationService instantiationService: IInstantiationService ) { - super(lifecycleService, contextService, configurationService, telemetryService, editorGroupService, editorService, fileService, untitledEditorService, instantiationService); + super(lifecycleService, contextService, configurationService, telemetryService, editorGroupService, fileService, untitledEditorService, instantiationService); } public setPromptPath(path: string): void { @@ -179,6 +181,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(IMessageService, new TestMessageService()); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); + instantiationService.stub(ITextModelResolverService, instantiationService.createInstance(TextModelResolverService)); return instantiationService; } @@ -236,6 +239,10 @@ export class TestPartService implements IPartService { return null; } + public isTitleBarHidden(): boolean { + return false; + } + public isStatusBarHidden(): boolean { return false; } @@ -474,14 +481,6 @@ export class TestEditorService implements IWorkbenchEditorService { return TPromise.as(null); } - public resolveEditorModel(input: IEditorInput, refresh?: boolean): TPromise; - public resolveEditorModel(input: IResourceInput, refresh?: boolean): TPromise; - public resolveEditorModel(input: any, refresh?: boolean): Promise { - this.callback('resolveEditorModel'); - - return input.resolve(refresh); - } - public closeEditor(position: Position, input: IEditorInput): TPromise { this.callback('closeEditor'); diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 538ad400800..7b0619eac00 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -2688,6 +2688,21 @@ declare module 'vscode' { */ has(section: string): boolean; + /** + * Retrieve all information about a configuration setting. A configuration value + * often consists of a *default* value, a global or installation-wide value, and + * a workspace-specific value. The *effective* value (returned by [`get`](#WorkspaceConfiguration.get)) + * is computed like this: `defaultValue` overwritten by `globalValue`, + * `globalValue` overwritten by `workspaceValue`. + * + * *Note:* The configuration name must denote a leaf in the configuration tree + * (`editor.fontSize` vs `editor`) otherwise no result is returned. + * + * @param section Configuration name, supports _dotted_ names. + * @return Information about a configuration setting or `undefined`. + */ + inspect(section: string): { key: string; defaultValue?: T; globalValue?: T; workspaceValue?: T }; + /** * Update a configuration value. A value can be changed for the current * [workspace](#workspace.rootPath) only, or globally for all instances of the diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 8ef3e391451..366e8113ed1 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -9,6 +9,7 @@ import { TrieMap } from 'vs/base/common/map'; import { score } from 'vs/editor/common/modes/languageSelector'; import * as Platform from 'vs/base/common/platform'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; +import { WorkspaceConfigurationNode } from 'vs/workbench/services/configuration/common/configuration'; import * as errors from 'vs/base/common/errors'; import product from 'vs/platform/product'; import pkg from 'vs/platform/package'; @@ -42,16 +43,16 @@ import * as vscode from 'vscode'; import * as paths from 'vs/base/common/paths'; import { realpathSync } from 'fs'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; -import { MainContext, ExtHostContext, InstanceCollection, IInitConfiguration } from './extHost.protocol'; +import { MainContext, ExtHostContext, InstanceCollection } from './extHost.protocol'; import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration'; export interface IExtensionApiFactory { - (extension?: IExtensionDescription): typeof vscode; + (extension: IExtensionDescription): typeof vscode; } function proposedApiFunction(extension: IExtensionDescription, fn: T): T { - if (extension && extension.enableProposedApi) { + if (extension.enableProposedApi) { return fn; } else { return (() => { @@ -63,7 +64,7 @@ function proposedApiFunction(extension: IExtensionDescription, fn: T): T { /** * This method instantiates and returns the extension API surface */ -export function createApiFactory(initDataConfiguration: IInitConfiguration, initTelemetryInfo: ITelemetryInfo, threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService): IExtensionApiFactory { +export function createApiFactory(initDataConfiguration: WorkspaceConfigurationNode, initTelemetryInfo: ITelemetryInfo, threadService: IThreadService, extensionService: ExtHostExtensionService, contextService: IWorkspaceContextService): IExtensionApiFactory { // Addressable instances const col = new InstanceCollection(); @@ -92,9 +93,9 @@ export function createApiFactory(initDataConfiguration: IInitConfiguration, init // Register API-ish commands ExtHostApiCommands.register(extHostCommands); - return function (extension?: IExtensionDescription): typeof vscode { + return function (extension: IExtensionDescription): typeof vscode { - if (extension && extension.enableProposedApi) { + if (extension.enableProposedApi) { console.warn(`${extension.name} (${extension.id}) uses PROPOSED API which is subject to change and removal without notice`); } @@ -204,7 +205,7 @@ export function createApiFactory(initDataConfiguration: IInitConfiguration, init return languageFeatures.registerSignatureHelpProvider(selector, provider, triggerCharacters); }, registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable { - return languageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters); + return languageFeatures.registerCompletionItemProvider(selector, provider, triggerCharacters, extension.id); }, registerDocumentLinkProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable { return languageFeatures.registerDocumentLinkProvider(selector, provider); @@ -460,8 +461,23 @@ export function defineAPI(factory: IExtensionApiFactory, extensionService: ExtHo // fall back to a default implementation if (!defaultApiImpl) { - defaultApiImpl = factory(undefined); + defaultApiImpl = factory(nullExtensionDescription); } return defaultApiImpl; }; } + +const nullExtensionDescription: IExtensionDescription = { + id: 'nullExtensionDescription', + name: 'Null Extension Description', + publisher: 'vscode', + activationEvents: undefined, + contributes: undefined, + enableProposedApi: false, + engines: undefined, + extensionDependencies: undefined, + extensionFolderPath: undefined, + isBuiltin: false, + main: undefined, + version: undefined +}; diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 403f1f96615..012d6603b64 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -29,6 +29,7 @@ import * as modes from 'vs/editor/common/modes'; import { IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { WorkspaceConfigurationNode } from 'vs/workbench/services/configuration/common/configuration'; import { IPickOpenEntry, IPickOptions } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; @@ -43,10 +44,6 @@ export interface IEnvironment { extensionTestsPath: string; } -export interface IInitConfiguration { - _initConfigurationBrand: void; -} - export interface IInitData { parentPid: number; environment: IEnvironment; @@ -54,7 +51,7 @@ export interface IInitData { workspace: IWorkspace; }; extensions: IExtensionDescription[]; - configuration: IInitConfiguration; + configuration: WorkspaceConfigurationNode; telemetryInfo: ITelemetryInfo; } @@ -232,7 +229,7 @@ export abstract class ExtHostCommandsShape { } export abstract class ExtHostConfigurationShape { - $acceptConfigurationChanged(config: any) { throw ni(); } + $acceptConfigurationChanged(config: WorkspaceConfigurationNode) { throw ni(); } } export abstract class ExtHostDiagnosticsShape { diff --git a/src/vs/workbench/api/node/extHostApiCommands.ts b/src/vs/workbench/api/node/extHostApiCommands.ts index c270f87afd0..5fca8b0a243 100644 --- a/src/vs/workbench/api/node/extHostApiCommands.ts +++ b/src/vs/workbench/api/node/extHostApiCommands.ts @@ -188,7 +188,7 @@ export class ExtHostApiCommands { return this._commands.executeCommand('_files.openFolderPicker', forceNewWindow); } - return this._commands.executeCommand('_workbench.ipc', 'vscode:windowOpen', [[uri.fsPath], forceNewWindow]); + return this._commands.executeCommand('_files.windowOpen', [uri.fsPath], forceNewWindow); }, { description: 'Open a folder in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder unless the newWindow parameter is set to true.', args: [ diff --git a/src/vs/workbench/api/node/extHostConfiguration.ts b/src/vs/workbench/api/node/extHostConfiguration.ts index 662c14b0a04..c7d9a594fa6 100644 --- a/src/vs/workbench/api/node/extHostConfiguration.ts +++ b/src/vs/workbench/api/node/extHostConfiguration.ts @@ -9,24 +9,25 @@ import Event, { Emitter } from 'vs/base/common/event'; import { WorkspaceConfiguration } from 'vscode'; import { ExtHostConfigurationShape, MainThreadConfigurationShape } from './extHost.protocol'; import { ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { WorkspaceConfigurationNode, IWorkspaceConfigurationValue } from 'vs/workbench/services/configuration/common/configuration'; export class ExtHostConfiguration extends ExtHostConfigurationShape { private _proxy: MainThreadConfigurationShape; - private _config: any; + private _config: WorkspaceConfigurationNode; private _onDidChangeConfiguration = new Emitter(); - constructor(proxy: MainThreadConfigurationShape, configuration: any) { + constructor(proxy: MainThreadConfigurationShape, config: WorkspaceConfigurationNode) { super(); this._proxy = proxy; - this._config = configuration; + this._config = config; } get onDidChangeConfiguration(): Event { return this._onDidChangeConfiguration && this._onDidChangeConfiguration.event; } - public $acceptConfigurationChanged(config: any) { + public $acceptConfigurationChanged(config: WorkspaceConfigurationNode) { this._config = config; this._onDidChangeConfiguration.fire(undefined); } @@ -39,14 +40,17 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape { const result: WorkspaceConfiguration = { has(key: string): boolean { - return typeof ExtHostConfiguration._lookUp(key, config) !== 'undefined'; + return typeof ExtHostConfiguration._lookUp(key, config) !== 'undefined'; }, - get(key: string, defaultValue?: T): T { - let result = ExtHostConfiguration._lookUp(key, config); + get(key: string, defaultValue?: T): any { + let result = ExtHostConfiguration._lookUp(key, config); if (typeof result === 'undefined') { - result = defaultValue; + return defaultValue; + } else if (isConfigurationValue(result)) { + return result.value; + } else { + return ExtHostConfiguration._values(result); } - return result; }, update: (key: string, value: any, global: boolean = false) => { key = section ? `${section}.${key}` : key; @@ -56,26 +60,66 @@ export class ExtHostConfiguration extends ExtHostConfigurationShape { } else { return this._proxy.$removeConfigurationOption(target, key); } + }, + inspect(key: string) { + let result = ExtHostConfiguration._lookUp(key, config); + if (isConfigurationValue(result)) { + return { + key: section ? `${section}.${key}` : key, + defaultValue: result.default, + globalValue: result.user, + workspaceValue: result.workspace + }; + } } }; - if (typeof config === 'object') { - mixin(result, config, false); + if (!isConfigurationValue(config)) { + mixin(result, ExtHostConfiguration._values(config), false); } return Object.freeze(result); + } - private static _lookUp(section: string, config: any) { + private static _lookUp(section: string, config: WorkspaceConfigurationNode): WorkspaceConfigurationNode | IWorkspaceConfigurationValue { if (!section) { return; } let parts = section.split('.'); let node = config; while (node && parts.length) { - node = node[parts.shift()]; + let child = node[parts.shift()]; + if (isConfigurationValue(child)) { + return child; + } else { + node = child; + } } return node; } + + private static _values(node: WorkspaceConfigurationNode): any { + let target = Object.create(null); + for (let key in node) { + let child = node[key]; + if (isConfigurationValue(child)) { + target[key] = child.value; + } else { + target[key] = ExtHostConfiguration._values(child); + } + } + return target; + } +} + +function isConfigurationValue(thing: any): thing is IWorkspaceConfigurationValue { + return typeof thing === 'object' + // must have 'value' + && typeof (>thing).value !== 'undefined' + // and at least one source 'default', 'user', or 'workspace' + && (typeof (>thing).default !== 'undefined' + || typeof (>thing).user !== 'undefined' + || typeof (>thing).workspace !== 'undefined'); } diff --git a/src/vs/workbench/api/node/extHostLanguageFeatures.ts b/src/vs/workbench/api/node/extHostLanguageFeatures.ts index 4c079b8470b..944f1564299 100644 --- a/src/vs/workbench/api/node/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/node/extHostLanguageFeatures.ts @@ -412,12 +412,14 @@ class SuggestAdapter { private _commands: CommandsConverter; private _heapService: ExtHostHeapService; private _provider: vscode.CompletionItemProvider; + private _extensionId: string; - constructor(documents: ExtHostDocuments, commands: CommandsConverter, heapService: ExtHostHeapService, provider: vscode.CompletionItemProvider) { + constructor(documents: ExtHostDocuments, commands: CommandsConverter, heapService: ExtHostHeapService, provider: vscode.CompletionItemProvider, extensionId?: string) { this._documents = documents; this._commands = commands; this._heapService = heapService; this._provider = provider; + this._extensionId = extensionId; } provideCompletionItems(resource: URI, position: IPosition): TPromise { @@ -477,6 +479,10 @@ class SuggestAdapter { suggestion.overwriteAfter = 0; } + if (this._extensionId) { + suggestion._extensionId = this._extensionId; + } + // store suggestion result.suggestions.push(suggestion); } @@ -771,9 +777,9 @@ export class ExtHostLanguageFeatures extends ExtHostLanguageFeaturesShape { // --- suggestion - registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable { + registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[], extensionId?: string): vscode.Disposable { const handle = this._nextHandle(); - this._adapter[handle] = new SuggestAdapter(this._documents, this._commands.converter, this._heapService, provider); + this._adapter[handle] = new SuggestAdapter(this._documents, this._commands.converter, this._heapService, provider, extensionId); this._proxy.$registerSuggestSupport(handle, selector, triggerCharacters); return this._createDisposable(handle); } diff --git a/src/vs/workbench/api/node/mainThreadConfiguration.ts b/src/vs/workbench/api/node/mainThreadConfiguration.ts index 39a5c31f124..45b530920f8 100644 --- a/src/vs/workbench/api/node/mainThreadConfiguration.ts +++ b/src/vs/workbench/api/node/mainThreadConfiguration.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; -import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkspaceConfigurationService, getWorkspaceConfigurationTree } from 'vs/workbench/services/configuration/common/configuration'; import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; import { MainThreadConfigurationShape, ExtHostContext } from './extHost.protocol'; @@ -24,7 +24,11 @@ export class MainThreadConfiguration extends MainThreadConfigurationShape { super(); this._configurationEditingService = configurationEditingService; const proxy = threadService.get(ExtHostContext.ExtHostConfiguration); - this._toDispose = configurationService.onDidUpdateConfiguration(event => proxy.$acceptConfigurationChanged(event.config)); + + this._toDispose = configurationService.onDidUpdateConfiguration(() => { + const tree = getWorkspaceConfigurationTree(configurationService); + proxy.$acceptConfigurationChanged(tree); + }); } public dispose(): void { diff --git a/src/vs/workbench/api/node/mainThreadDocuments.ts b/src/vs/workbench/api/node/mainThreadDocuments.ts index eb25df0e6d4..17f6e3f9f6c 100644 --- a/src/vs/workbench/api/node/mainThreadDocuments.ts +++ b/src/vs/workbench/api/node/mainThreadDocuments.ts @@ -19,12 +19,13 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IFileService } from 'vs/platform/files/common/files'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { ExtHostContext, MainThreadDocumentsShape, ExtHostDocumentsShape } from './extHost.protocol'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; export class MainThreadDocuments extends MainThreadDocumentsShape { private _modelService: IModelService; private _modeService: IModeService; + private _textModelResolverService: ITextModelResolverService; private _textFileService: ITextFileService; private _editorService: IWorkbenchEditorService; private _fileService: IFileService; @@ -44,11 +45,13 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { @ITextFileService textFileService: ITextFileService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, + @ITextModelResolverService textModelResolverService: ITextModelResolverService, @IUntitledEditorService untitledEditorService: IUntitledEditorService ) { super(); this._modelService = modelService; this._modeService = modeService; + this._textModelResolverService = textModelResolverService; this._textFileService = textFileService; this._editorService = editorService; this._fileService = fileService; @@ -184,7 +187,7 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { } private _handleAsResourceInput(uri: URI): TPromise { - return this._editorService.resolveEditorModel({ resource: uri }).then(model => { + return this._textModelResolverService.resolve(uri).then(model => { return !!model; }); } @@ -213,7 +216,7 @@ export class MainThreadDocuments extends MainThreadDocumentsShape { // --- virtual document logic $registerTextContentProvider(handle: number, scheme: string): void { - this._resourceContentProvider[handle] = ResourceEditorInput.registerResourceContentProvider(scheme, { + this._resourceContentProvider[handle] = this._textModelResolverService.registerTextModelContentProvider(scheme, { provideTextContent: (uri: URI): TPromise => { return this._proxy.$provideTextDocumentContent(handle, uri).then(value => { if (typeof value === 'string') { diff --git a/src/vs/workbench/api/node/mainThreadSaveParticipant.ts b/src/vs/workbench/api/node/mainThreadSaveParticipant.ts index 5e1f28bbf11..e07ed69d1da 100644 --- a/src/vs/workbench/api/node/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/node/mainThreadSaveParticipant.ts @@ -7,6 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { sequence } from 'vs/base/common/async'; +import * as strings from 'vs/base/common/strings'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; import { IThreadService } from 'vs/workbench/services/thread/common/threadService'; import { ISaveParticipant, ITextFileEditorModel, SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; @@ -21,8 +22,9 @@ import { EditOperationsCommand } from 'vs/editor/contrib/format/common/formatCom import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { ExtHostContext, ExtHostDocumentSaveParticipantShape } from './extHost.protocol'; +import { EditOperation } from 'vs/editor/common/core/editOperation'; -interface INamedSaveParticpant extends ISaveParticipant { +export interface INamedSaveParticpant extends ISaveParticipant { readonly name: string; } @@ -47,29 +49,18 @@ class TrimWhitespaceParticipant implements INamedSaveParticpant { let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)]; const cursors: IPosition[] = []; - // Find `prevSelection` in any case do ensure a good undo stack when pushing the edit - // Collect active cursors in `cursors` only if `isAutoSaved` to avoid having the cursors jump - if (model.isAttachedToEditor()) { - const allEditors = this.codeEditorService.listCodeEditors(); - for (let i = 0, len = allEditors.length; i < len; i++) { - const editor = allEditors[i]; - const editorModel = editor.getModel(); - - if (!editorModel) { - continue; // empty editor - } - - if (model === editorModel) { - prevSelection = editor.getSelections(); - if (isAutoSaved) { - cursors.push(...prevSelection.map(s => { - return { - lineNumber: s.positionLineNumber, - column: s.positionColumn - }; - })); - } - } + let editor = findEditor(model, this.codeEditorService); + if (editor) { + // Find `prevSelection` in any case do ensure a good undo stack when pushing the edit + // Collect active cursors in `cursors` only if `isAutoSaved` to avoid having the cursors jump + prevSelection = editor.getSelections(); + if (isAutoSaved) { + cursors.push(...prevSelection.map(s => { + return { + lineNumber: s.positionLineNumber, + column: s.positionColumn + }; + })); } } @@ -82,6 +73,62 @@ class TrimWhitespaceParticipant implements INamedSaveParticpant { } } +function findEditor(model: IModel, codeEditorService: ICodeEditorService): ICommonCodeEditor { + if (model.isAttachedToEditor()) { + const allEditors = codeEditorService.listCodeEditors(); + for (let i = 0, len = allEditors.length; i < len; i++) { + const editor = allEditors[i]; + const editorModel = editor.getModel(); + + if (!editorModel) { + continue; // empty editor + } + + if (model === editorModel) { + return editor; + } + } + } + + return null; +} + +export class FinalNewLineParticipant implements INamedSaveParticpant { + + readonly name = 'FinalNewLineParticipant'; + + constructor( + @IConfigurationService private configurationService: IConfigurationService, + @ICodeEditorService private codeEditorService: ICodeEditorService + ) { + // Nothing + } + + public participate(model: ITextFileEditorModel, env: { reason: SaveReason }): any { + if (this.configurationService.lookup('files.insertFinalNewline').value) { + this.doInsertFinalNewLine(model.textEditorModel); + } + } + + private doInsertFinalNewLine(model: IModel): void { + const lineCount = model.getLineCount(); + const lastLine = model.getLineContent(lineCount); + const lastLineIsEmptyOrWhitespace = strings.lastNonWhitespaceIndex(lastLine) === -1; + + if (!lineCount || lastLineIsEmptyOrWhitespace) { + return; + } + + let prevSelection: Selection[] = [new Selection(1, 1, 1, 1)]; + const editor = findEditor(model, this.codeEditorService); + if (editor) { + prevSelection = editor.getSelections(); + } + + model.pushEditOperations(prevSelection, [EditOperation.insert({ lineNumber: lineCount + 1, column: 0 }, model.getEOL())], (edits) => prevSelection); + } +} + class FormatOnSaveParticipant implements INamedSaveParticpant { readonly name = 'FormatOnSaveParticipant'; @@ -204,6 +251,7 @@ export class SaveParticipant implements ISaveParticipant { this._saveParticipants = [ instantiationService.createInstance(TrimWhitespaceParticipant), + instantiationService.createInstance(FinalNewLineParticipant), instantiationService.createInstance(FormatOnSaveParticipant), instantiationService.createInstance(ExtHostSaveParticipant) ]; diff --git a/src/vs/workbench/api/node/mainThreadWorkspace.ts b/src/vs/workbench/api/node/mainThreadWorkspace.ts index e7ed8276620..ca48df3618e 100644 --- a/src/vs/workbench/api/node/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/node/mainThreadWorkspace.ts @@ -15,6 +15,7 @@ import { bulkEdit, IResourceEdit } from 'vs/editor/common/services/bulkEdit'; import { TPromise } from 'vs/base/common/winjs.base'; import { Uri } from 'vscode'; import { MainThreadWorkspaceShape } from './extHost.protocol'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; export class MainThreadWorkspace extends MainThreadWorkspaceShape { @@ -23,6 +24,7 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape { private _workspace: IWorkspace; private _textFileService: ITextFileService; private _editorService: IWorkbenchEditorService; + private _textModelResolverService: ITextModelResolverService; private _eventService: IEventService; constructor( @@ -30,6 +32,7 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape { @IWorkspaceContextService contextService: IWorkspaceContextService, @ITextFileService textFileService, @IWorkbenchEditorService editorService, + @ITextModelResolverService textModelResolverService, @IEventService eventService ) { super(); @@ -39,6 +42,7 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape { this._textFileService = textFileService; this._editorService = editorService; this._eventService = eventService; + this._textModelResolverService = textModelResolverService; } $startSearch(include: string, exclude: string, maxResults: number, requestId: number): Thenable { @@ -95,7 +99,7 @@ export class MainThreadWorkspace extends MainThreadWorkspaceShape { } } - return bulkEdit(this._eventService, this._editorService, codeEditor, edits) + return bulkEdit(this._eventService, this._textModelResolverService, codeEditor, edits) .then(() => true); } } diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index f034303e5e7..39df26dca1c 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { Dimension, Builder, Box } from 'vs/base/browser/builder'; +import { Dimension, Builder } from 'vs/base/browser/builder'; import { Part } from 'vs/workbench/browser/part'; import { QuickOpenController } from 'vs/workbench/browser/parts/quickopen/quickOpenController'; import { Sash, ISashEvent, IVerticalSashLayoutProvider, IHorizontalSashLayoutProvider, Orientation } from 'vs/base/browser/ui/sash/sash'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IPartService, Position } from 'vs/workbench/services/part/common/partService'; +import { IPartService, Position, ILayoutOptions } from 'vs/workbench/services/part/common/partService'; import { IViewletService } from 'vs/workbench/services/viewlet/common/viewletService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; @@ -18,6 +18,7 @@ import { IThemeService } from 'vs/workbench/services/themes/common/themeService' import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { getZoomFactor } from 'vs/base/browser/browser'; const DEFAULT_MIN_SIDEBAR_PART_WIDTH = 170; const DEFAULT_MIN_PANEL_PART_HEIGHT = 77; @@ -27,33 +28,15 @@ const DEFAULT_PANEL_HEIGHT_COEFFICIENT = 0.4; const HIDE_SIDEBAR_WIDTH_THRESHOLD = 50; const HIDE_PANEL_HEIGHT_THRESHOLD = 50; -export class LayoutOptions { - public margin: Box; - - constructor() { - this.margin = new Box(0, 0, 0, 0); - } - - public setMargin(margin: Box): LayoutOptions { - this.margin = margin; - - return this; - } -} - interface ComputedStyles { - activitybar: { minWidth: number; }; + titlebar: { height: number; }; + activitybar: { width: number; }; sidebar: { minWidth: number; }; panel: { minHeight: number; }; editor: { minWidth: number; minHeight: number; }; statusbar: { height: number; }; } -export interface ILayoutOptions { - forceStyleReCompute?: boolean; - toggleMaximizedPanel?: boolean; -} - /** * The workbench layout is responsible to lay out all parts that make the Workbench. */ @@ -65,22 +48,25 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal private parent: Builder; private workbenchContainer: Builder; + private titlebar: Part; private activitybar: Part; private editor: Part; private sidebar: Part; private panel: Part; private statusbar: Part; private quickopen: QuickOpenController; - private options: LayoutOptions; private toUnbind: IDisposable[]; private computedStyles: ComputedStyles; + private initialComputedStyles: ComputedStyles; private workbenchSize: Dimension; private sashX: Sash; private sashY: Sash; - private activityBarWidth: number; private startSidebarWidth: number; private sidebarWidth: number; private sidebarHeight: number; + private titlebarHeight: number; + private activitybarWidth: number; + private statusbarHeight: number; private startPanelHeight: number; private panelHeight: number; private panelHeightBeforeMaximized: number; @@ -92,6 +78,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal parent: Builder, workbenchContainer: Builder, parts: { + titlebar: Part, activitybar: Part, editor: Part, sidebar: Part, @@ -99,7 +86,6 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal statusbar: Part }, quickopen: QuickOpenController, - options: LayoutOptions, @IStorageService private storageService: IStorageService, @IEventService eventService: IEventService, @IContextViewService private contextViewService: IContextViewService, @@ -112,13 +98,13 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal ) { this.parent = parent; this.workbenchContainer = workbenchContainer; + this.titlebar = parts.titlebar; this.activitybar = parts.activitybar; this.editor = parts.editor; this.sidebar = parts.sidebar; this.panel = parts.panel; this.statusbar = parts.statusbar; this.quickopen = quickopen; - this.options = options || new LayoutOptions(); this.toUnbind = []; this.computedStyles = null; @@ -132,7 +118,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal }); let isActivityBarHidden = this.partService.isActivityBarHidden(); - this.activityBarWidth = isActivityBarHidden ? 0 : this.storageService.getInteger(WorkbenchLayout.activityBarWidthSettingsKey, StorageScope.GLOBAL, 50); + this.activitybarWidth = isActivityBarHidden ? 0 : this.storageService.getInteger(WorkbenchLayout.activityBarWidthSettingsKey, StorageScope.GLOBAL, 50); this.sidebarWidth = this.storageService.getInteger(WorkbenchLayout.sashXWidthSettingsKey, StorageScope.GLOBAL, -1); this.panelHeight = this.storageService.getInteger(WorkbenchLayout.sashYHeightSettingsKey, StorageScope.GLOBAL, 0); @@ -172,7 +158,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal if (newSashWidth + HIDE_SIDEBAR_WIDTH_THRESHOLD < this.computedStyles.sidebar.minWidth) { let dragCompensation = DEFAULT_MIN_SIDEBAR_PART_WIDTH - HIDE_SIDEBAR_WIDTH_THRESHOLD; this.partService.setSideBarHidden(true); - startX = (sidebarPosition === Position.LEFT) ? Math.max(this.activityBarWidth, e.currentX - dragCompensation) : Math.min(e.currentX + dragCompensation, this.workbenchSize.width - this.activityBarWidth); + startX = (sidebarPosition === Position.LEFT) ? Math.max(this.activitybarWidth, e.currentX - dragCompensation) : Math.min(e.currentX + dragCompensation, this.workbenchSize.width - this.activitybarWidth); this.sidebarWidth = this.startSidebarWidth; // when restoring sidebar, restore to the sidebar width we started from } @@ -201,17 +187,16 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.sashY.addListener2('change', (e: ISashEvent) => { let doLayout = false; let isPanelHidden = this.partService.isPanelHidden(); - let isStatusbarHidden = this.partService.isStatusBarHidden(); let newSashHeight = this.startPanelHeight - (e.currentY - startY); // Panel visible if (!isPanelHidden) { + // Automatically hide panel when a certain threshold is met if (newSashHeight + HIDE_PANEL_HEIGHT_THRESHOLD < this.computedStyles.panel.minHeight) { let dragCompensation = DEFAULT_MIN_PANEL_PART_HEIGHT - HIDE_PANEL_HEIGHT_THRESHOLD; this.partService.setPanelHidden(true); - let statusbarHeight = isStatusbarHidden ? 0 : this.computedStyles.statusbar.height; - startY = Math.min(this.sidebarHeight - statusbarHeight, e.currentY + dragCompensation); + startY = Math.min(this.sidebarHeight - this.statusbarHeight - this.titlebarHeight, e.currentY + dragCompensation); this.panelHeight = this.startPanelHeight; // when restoring panel, restore to the panel height we started from } @@ -303,38 +288,44 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal } private computeStyle(): void { + const titlebarStyle = this.titlebar.getContainer().getComputedStyle(); const sidebarStyle = this.sidebar.getContainer().getComputedStyle(); const panelStyle = this.panel.getContainer().getComputedStyle(); const editorStyle = this.editor.getContainer().getComputedStyle(); const activitybarStyle = this.activitybar.getContainer().getComputedStyle(); const statusbarStyle = this.statusbar.getContainer().getComputedStyle(); + // Determine styles by looking into their CSS this.computedStyles = { - activitybar: { - minWidth: parseInt(activitybarStyle.getPropertyValue('min-width'), 10) || 0 + titlebar: { + height: parseInt(titlebarStyle.getPropertyValue('height'), 10) + }, + activitybar: { + width: parseInt(activitybarStyle.getPropertyValue('width'), 10) }, - sidebar: { minWidth: parseInt(sidebarStyle.getPropertyValue('min-width'), 10) || DEFAULT_MIN_SIDEBAR_PART_WIDTH }, - panel: { minHeight: parseInt(panelStyle.getPropertyValue('min-height'), 10) || DEFAULT_MIN_PANEL_PART_HEIGHT }, - editor: { minWidth: parseInt(editorStyle.getPropertyValue('min-width'), 10) || DEFAULT_MIN_EDITOR_PART_WIDTH, minHeight: DEFAULT_MIN_EDITOR_PART_HEIGHT }, - statusbar: { - height: parseInt(statusbarStyle.getPropertyValue('height'), 10) || 18 + height: parseInt(statusbarStyle.getPropertyValue('height'), 10) } }; + + // Always keep the initial computed styles + if (!this.initialComputedStyles) { + this.initialComputedStyles = this.computedStyles; + } } public layout(options?: ILayoutOptions): void { - if (options && options.forceStyleReCompute) { + if (options && options.forceStyleRecompute) { this.computeStyle(); this.editor.getLayout().computeStyle(); this.sidebar.getLayout().computeStyle(); @@ -364,20 +355,18 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.sidebarWidth = sidebarWidth; } - let statusbarHeight = isStatusbarHidden ? 0 : this.computedStyles.statusbar.height; + this.statusbarHeight = isStatusbarHidden ? 0 : this.computedStyles.statusbar.height; + this.titlebarHeight = this.initialComputedStyles.titlebar.height / getZoomFactor(); // adjust for zoom prevention - this.sidebarHeight = this.workbenchSize.height - statusbarHeight; + this.sidebarHeight = this.workbenchSize.height - this.statusbarHeight - this.titlebarHeight; let sidebarSize = new Dimension(sidebarWidth, this.sidebarHeight); // Activity Bar - let activityBarMinWidth = this.computedStyles.activitybar.minWidth; - let activityBarWidth: number; + this.activitybarWidth = this.computedStyles.activitybar.width; if (isActivityBarHidden) { - activityBarWidth = 0; - } else { - activityBarWidth = activityBarMinWidth; + this.activitybarWidth = 0; } - let activityBarSize = new Dimension(activityBarWidth, sidebarSize.height); + let activityBarSize = new Dimension(this.activitybarWidth, sidebarSize.height); // Panel part let panelHeight: number; @@ -410,7 +399,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Sidebar hidden if (isSidebarHidden) { - editorSize.width = this.workbenchSize.width - activityBarSize.width; + editorSize.width = Math.min(this.workbenchSize.width - activityBarSize.width, this.workbenchSize.width - this.activitybarWidth); if (sidebarPosition === Position.LEFT) { editorSize.remainderLeft = Math.round((this.workbenchSize.width - editorSize.width + activityBarSize.width) / 2); @@ -449,8 +438,8 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal } if (!isActivityBarHidden) { - this.activityBarWidth = activityBarSize.width; - this.storageService.store(WorkbenchLayout.activityBarWidthSettingsKey, this.activityBarWidth, StorageScope.GLOBAL); + this.activitybarWidth = activityBarSize.width; + this.storageService.store(WorkbenchLayout.activityBarWidthSettingsKey, this.activitybarWidth, StorageScope.GLOBAL); } if (!isSidebarHidden) { @@ -465,7 +454,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal // Workbench this.workbenchContainer - .position(this.options.margin.top, this.options.margin.right, this.options.margin.bottom, this.options.margin.left, 'relative') + .position(0, 0, 0, 0, 'relative') .size(this.workbenchSize.width, this.workbenchSize.height); // Bug on Chrome: Sometimes Chrome wants to scroll the workbench container on layout changes. The fix is to reset scrolling in this case. @@ -481,39 +470,39 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.editor.getContainer().size(editorSize.width, editorSize.height); this.panel.getContainer().size(panelDimension.width, panelDimension.height); - const editorBottom = statusbarHeight + panelDimension.height; + const editorBottom = this.statusbarHeight + panelDimension.height; if (isSidebarHidden) { - this.editor.getContainer().position(0, editorSize.remainderRight, editorBottom, editorSize.remainderLeft); - this.panel.getContainer().position(editorSize.height, editorSize.remainderRight, statusbarHeight, editorSize.remainderLeft); + this.editor.getContainer().position(this.titlebarHeight, editorSize.remainderRight, editorBottom, editorSize.remainderLeft); + this.panel.getContainer().position(editorSize.height + this.titlebarHeight, editorSize.remainderRight, this.statusbarHeight, editorSize.remainderLeft); } else if (sidebarPosition === Position.LEFT) { - this.editor.getContainer().position(0, 0, editorBottom, sidebarSize.width + activityBarSize.width); - this.panel.getContainer().position(editorSize.height, 0, statusbarHeight, sidebarSize.width + activityBarSize.width); + this.editor.getContainer().position(this.titlebarHeight, 0, editorBottom, sidebarSize.width + activityBarSize.width); + this.panel.getContainer().position(editorSize.height + this.titlebarHeight, 0, this.statusbarHeight, sidebarSize.width + activityBarSize.width); } else { - this.editor.getContainer().position(0, sidebarSize.width, editorBottom, 0); - this.panel.getContainer().position(editorSize.height, sidebarSize.width, statusbarHeight, 0); + this.editor.getContainer().position(this.titlebarHeight, sidebarSize.width, editorBottom, 0); + this.panel.getContainer().position(editorSize.height + this.titlebarHeight, sidebarSize.width, this.statusbarHeight, 0); } // Activity Bar Part this.activitybar.getContainer().size(null, activityBarSize.height); if (sidebarPosition === Position.LEFT) { this.activitybar.getContainer().getHTMLElement().style.right = ''; - this.activitybar.getContainer().position(0, null, 0, 0); + this.activitybar.getContainer().position(this.titlebarHeight, null, 0, 0); } else { this.activitybar.getContainer().getHTMLElement().style.left = ''; - this.activitybar.getContainer().position(0, 0, 0, null); + this.activitybar.getContainer().position(this.titlebarHeight, 0, 0, null); } // Sidebar Part this.sidebar.getContainer().size(sidebarSize.width, sidebarSize.height); if (sidebarPosition === Position.LEFT) { - this.sidebar.getContainer().position(0, editorSize.width, 0, activityBarSize.width); + this.sidebar.getContainer().position(this.titlebarHeight, editorSize.width, 0, activityBarSize.width); } else { - this.sidebar.getContainer().position(0, null, 0, editorSize.width); + this.sidebar.getContainer().position(this.titlebarHeight, null, 0, editorSize.width); } // Statusbar Part - this.statusbar.getContainer().position(this.workbenchSize.height - statusbarHeight); + this.statusbar.getContainer().position(this.workbenchSize.height - this.statusbarHeight); // Quick open this.quickopen.layout(this.workbenchSize); @@ -523,6 +512,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal this.sashY.layout(); // Propagate to Part Layouts + this.titlebar.layout(new Dimension(this.workbenchSize.width, this.titlebarHeight)); this.editor.layout(new Dimension(editorSize.width, editorSize.height)); this.sidebar.layout(sidebarSize); this.panel.layout(panelDimension); @@ -537,24 +527,22 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal let clientArea = this.parent.getClientArea(); // Workbench: Client Area - Margins - return clientArea.substract(this.options.margin); + return clientArea; } public getVerticalSashTop(sash: Sash): number { - return 0; + return this.titlebarHeight; } public getVerticalSashLeft(sash: Sash): number { let isSidebarHidden = this.partService.isSideBarHidden(); let sidebarPosition = this.partService.getSideBarPosition(); - let isActivityBarHidden = this.partService.isActivityBarHidden(); - let activitybarWidth = !isActivityBarHidden ? this.computedStyles.activitybar.minWidth : 0; if (sidebarPosition === Position.LEFT) { - return !isSidebarHidden ? this.sidebarWidth + activitybarWidth : activitybarWidth; + return !isSidebarHidden ? this.sidebarWidth + this.activitybarWidth : this.activitybarWidth; } - return !isSidebarHidden ? this.workbenchSize.width - this.sidebarWidth - activitybarWidth : this.workbenchSize.width - activitybarWidth; + return !isSidebarHidden ? this.workbenchSize.width - this.sidebarWidth - this.activitybarWidth : this.workbenchSize.width - this.activitybarWidth; } public getVerticalSashHeight(sash: Sash): number { @@ -562,7 +550,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal } public getHorizontalSashTop(sash: Sash): number { - return 2 + (this.partService.isPanelHidden() ? this.sidebarHeight : this.sidebarHeight - this.panelHeight); // Horizontal sash should be a bit lower than the editor area, thus add 2px #5524 + return 2 + (this.partService.isPanelHidden() ? this.sidebarHeight + this.titlebarHeight : this.sidebarHeight - this.panelHeight + this.titlebarHeight); // Horizontal sash should be a bit lower than the editor area, thus add 2px #5524 } public getHorizontalSashLeft(sash: Sash): number { diff --git a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css index 636a2217c80..57c94dda124 100644 --- a/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css +++ b/src/vs/workbench/browser/parts/activitybar/media/activitybarpart.css @@ -5,7 +5,6 @@ .monaco-workbench > .part.activitybar { z-index: 20; - min-width: 50px; width: 50px; } diff --git a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts index 6f10424b692..c518a3053e8 100644 --- a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts @@ -18,7 +18,6 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorInput, EditorOptions, BINARY_DIFF_EDITOR_ID } from 'vs/workbench/common/editor'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { DiffEditorModel } from 'vs/workbench/common/editor/diffEditorModel'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; @@ -45,8 +44,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas private startLeftContainerWidth: number; constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService + @ITelemetryService telemetryService: ITelemetryService ) { super(BinaryResourceDiffEditor.ID, telemetryService); @@ -106,7 +104,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas } // Different Input (Reload) - return this.editorService.resolveEditorModel(input, true /* Reload */).then((resolvedModel: DiffEditorModel) => { + return input.resolve(true).then((resolvedModel: DiffEditorModel) => { // Assert model instance if (!(resolvedModel.originalModel instanceof BinaryEditorModel) || !(resolvedModel.modifiedModel instanceof BinaryEditorModel)) { diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index a957f308b04..ccf777af156 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -13,7 +13,6 @@ import { ResourceViewer } from 'vs/base/browser/ui/resourceviewer/resourceViewer import { EditorModel, EditorInput, EditorOptions } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; @@ -28,7 +27,10 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { private binaryContainer: Builder; private scrollbar: DomScrollableElement; - constructor(id: string, telemetryService: ITelemetryService, private _editorService: IWorkbenchEditorService) { + constructor( + id: string, + telemetryService: ITelemetryService + ) { super(id, telemetryService); this._onMetadataChanged = new Emitter(); @@ -42,10 +44,6 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { return this.getInput() ? this.getInput().getName() : nls.localize('binaryEditor', "Binary Viewer"); } - public get editorService() { - return this._editorService; - } - public createEditor(parent: Builder): void { // Container for Binary @@ -72,7 +70,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { } // Different Input (Reload) - return this._editorService.resolveEditorModel(input, true /* Reload */).then((resolvedModel: EditorModel) => { + return input.resolve(true).then((resolvedModel: EditorModel) => { // Assert Model instance if (!(resolvedModel instanceof BinaryEditorModel)) { @@ -141,9 +139,8 @@ export class BinaryResourceEditor extends BaseBinaryResourceEditor { public static ID = 'workbench.editors.binaryResourceEditor'; constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService + @ITelemetryService telemetryService: ITelemetryService ) { - super(BinaryResourceEditor.ID, telemetryService, editorService); + super(BinaryResourceEditor.ID, telemetryService); } } diff --git a/src/vs/workbench/browser/parts/editor/media/tabstitle.css b/src/vs/workbench/browser/parts/editor/media/tabstitle.css index 7ba8f69e7e1..b18efa9585a 100644 --- a/src/vs/workbench/browser/parts/editor/media/tabstitle.css +++ b/src/vs/workbench/browser/parts/editor/media/tabstitle.css @@ -171,6 +171,10 @@ width: 28px; } +.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab.no-close-button > .tab-close { + display: none; /* hide the close action bar when we are configured to hide it */ +} + .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title.active .tabs-container > .tab.active > .tab-close .action-label, /* always show it for active tab */ .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title.active .tabs-container > .tab > .tab-close .action-label:focus, /* always show it on focus */ .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title.active .tabs-container > .tab:hover > .tab-close .action-label, /* always show it on hover */ @@ -217,6 +221,27 @@ background: url('close-inverse.svg') center center no-repeat; } +/* No Tab Close Button */ + +.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab.no-close-button { + padding-right: 28px; /* make room for dirty indication when we are running without close button */ +} + +.monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab.no-close-button.dirty { + background-repeat: no-repeat; + background-position-y: center; + background-position-x: calc(100% - 6px); /* to the right of the tab label */ +} + +.vs .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab.no-close-button.dirty { + background-image: url('close-dirty.svg'); +} + +.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab.no-close-button.dirty, +.hc-black .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .tabs-container > .tab.no-close-button.dirty { + background-image: url('close-dirty-inverse.svg'); +} + /* Editor Actions */ .monaco-workbench > .part.editor > .content > .one-editor-silo > .container > .title .editor-actions { diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts index 9ba56be69d3..c92369e61a8 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts @@ -36,6 +36,7 @@ import { NoTabsTitleControl } from 'vs/workbench/browser/parts/editor/noTabsTitl import { IEditorStacksModel, IStacksModelChangeEvent, IWorkbenchEditorConfiguration, IEditorGroup, EditorOptions, TextEditorOptions, IEditorIdentifier } from 'vs/workbench/common/editor'; import { ITitleAreaControl } from 'vs/workbench/browser/parts/editor/titleControl'; import { extractResources } from 'vs/base/browser/dnd'; +import { IWindowService } from 'vs/platform/windows/common/windows'; export enum Rochade { NONE, @@ -110,6 +111,7 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti private layoutVertically: boolean; private showTabs: boolean; + private showTabCloseButton: boolean; private showIcons: boolean; private silos: Builder[]; @@ -146,7 +148,8 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti @IConfigurationService private configurationService: IConfigurationService, @IContextKeyService private contextKeyService: IContextKeyService, @IExtensionService private extensionService: IExtensionService, - @IInstantiationService private instantiationService: IInstantiationService + @IInstantiationService private instantiationService: IInstantiationService, + @IWindowService private windowService: IWindowService ) { this.stacks = editorGroupService.getStacksModel(); this.toDispose = []; @@ -216,11 +219,15 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti } private onConfigurationUpdated(config: IWorkbenchEditorConfiguration, refresh?: boolean): void { + const showTabCloseButton = this.showTabCloseButton; + if (config.workbench && config.workbench.editor) { this.showTabs = config.workbench.editor.showTabs; + this.showTabCloseButton = config.workbench.editor.showTabCloseButton; this.showIcons = config.workbench.editor.showIcons; } else { this.showTabs = true; + this.showTabCloseButton = true; this.showIcons = false; } @@ -259,7 +266,7 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti } // Refresh title when icons change - else if (showingIcons !== this.showIcons) { + else if (showingIcons !== this.showIcons || showTabCloseButton !== this.showTabCloseButton) { titleControl.refresh(true); } } @@ -998,10 +1005,8 @@ export class SideBySideEditorControl implements ISideBySideEditorControl, IVerti // Check for URI transfer else { if (droppedResources.length) { - window.focus(); // make sure this window has focus so that the open call reaches the right window! - - // Open all - editorService.openEditors(droppedResources.map(resource => { return { input: { resource, options: { pinned: true } }, position: splitEditor ? freeGroup : position }; })) + $this.windowService.focusWindow() + .then(() => editorService.openEditors(droppedResources.map(resource => { return { input: { resource, options: { pinned: true } }, position: splitEditor ? freeGroup : position }; }))) .then(() => { if (splitEditor && splitTo !== freeGroup) { groupService.moveGroup(freeGroup, splitTo); diff --git a/src/vs/workbench/browser/parts/editor/stringEditor.ts b/src/vs/workbench/browser/parts/editor/stringEditor.ts index 77359930e59..1654fc95136 100644 --- a/src/vs/workbench/browser/parts/editor/stringEditor.ts +++ b/src/vs/workbench/browser/parts/editor/stringEditor.ts @@ -93,7 +93,7 @@ export class StringEditor extends BaseTextEditor { } // Different Input (Reload) - return this.editorService.resolveEditorModel(input, true /* Reload */).then((resolvedModel: EditorModel) => { + return input.resolve(true).then((resolvedModel: EditorModel) => { // Assert Model instance if (!(resolvedModel instanceof BaseTextEditorModel)) { diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index 492eecb1ff1..b59abdf4bda 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -28,6 +28,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMenuService } from 'vs/platform/actions/common/actions'; +import { IWindowService } from 'vs/platform/windows/common/windows'; import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; @@ -65,7 +66,8 @@ export class TabsTitleControl extends TitleControl { @ITelemetryService telemetryService: ITelemetryService, @IMessageService messageService: IMessageService, @IMenuService menuService: IMenuService, - @IQuickOpenService quickOpenService: IQuickOpenService + @IQuickOpenService quickOpenService: IQuickOpenService, + @IWindowService private windowService: IWindowService ) { super(contextMenuService, instantiationService, configurationService, editorService, editorGroupService, contextKeyService, keybindingService, telemetryService, messageService, menuService, quickOpenService); @@ -337,6 +339,12 @@ export class TabsTitleControl extends TitleControl { DOM.addClass(tabContainer, 'tab monaco-editor-background'); tabContainers.push(tabContainer); + if (!this.showTabCloseButton) { + DOM.addClass(tabContainer, 'no-close-button'); + } else { + DOM.removeClass(tabContainer, 'no-close-button'); + } + // Tab Editor Label const editorLabel = this.instantiationService.createInstance(EditorLabel, tabContainer, void 0); this.editorLabels.push(editorLabel); @@ -537,6 +545,8 @@ export class TabsTitleControl extends TitleControl { } private onDrop(e: DragEvent, group: IEditorGroup, targetPosition: Position, targetIndex: number): void { + DOM.removeClass(this.tabsContainer, 'dropfeedback'); + DOM.removeClass(this.tabsContainer, 'scroll'); // Local DND const draggedEditor = TabsTitleControl.getDraggedEditor(); @@ -574,10 +584,10 @@ export class TabsTitleControl extends TitleControl { input: { resource, options: { pinned: true, index: targetIndex } }, position: targetPosition }; - })).done(() => { + })).then(() => { this.editorGroupService.focusGroup(targetPosition); - window.focus(); - }, errors.onUnexpectedError); + return this.windowService.focusWindow(); + }).done(null, errors.onUnexpectedError); } } diff --git a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts index 100ee9fe180..842473fcfdb 100644 --- a/src/vs/workbench/browser/parts/editor/textDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textDiffEditor.ts @@ -142,7 +142,7 @@ export class TextDiffEditor extends BaseTextEditor { } // Different Input (Reload) - return this.editorService.resolveEditorModel(input, true /* Reload */).then((resolvedModel: EditorModel) => { + return input.resolve(true).then((resolvedModel: EditorModel) => { // Assert Model Instance if (!(resolvedModel instanceof TextDiffEditorModel) && this.openAsBinary(input, options)) { diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index baae7dad1b6..b757f02912a 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -79,6 +79,7 @@ export abstract class TitleControl implements ITitleAreaControl { private previewEditors: boolean; private showTabs: boolean; + protected showTabCloseButton: boolean; private currentPrimaryEditorActionIds: string[] = []; private currentSecondaryEditorActionIds: string[] = []; @@ -154,6 +155,7 @@ export abstract class TitleControl implements ITitleAreaControl { private onConfigurationUpdated(config: IWorkbenchEditorConfiguration): void { this.previewEditors = config.workbench && config.workbench.editor && config.workbench.editor.enablePreview; this.showTabs = config.workbench && config.workbench.editor && config.workbench.editor.showTabs; + this.showTabCloseButton = config.workbench && config.workbench.editor && config.workbench.editor.showTabCloseButton; } private updateSplitActionEnablement(): void { diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index ef04a3e93ff..8523116bda5 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -247,7 +247,7 @@ class StatusBarEntryItem implements IStatusbarItem { action.dispose(); }, (err) => this.messageService.show(Severity.Error, toErrorMessage(err))); } else { - this.messageService.show(Severity.Warning, nls.localize('canNotRun', "Command '{0}' can not be run from here.", action.label || id)); + this.messageService.show(Severity.Warning, nls.localize('canNotRun', "Command '{0}' is currently not enabled and can not be run.", action.label || id)); } return; diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css new file mode 100644 index 00000000000..18ae6955a47 --- /dev/null +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -0,0 +1,68 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench > .part.titlebar { + box-sizing: border-box; + z-index: 80; + width: 100%; + font-size: 12px; + padding: 0 70px; + overflow: hidden; + flex-shrink: 0; + align-items: center; + justify-content: center; + -webkit-user-select: none; + -webkit-app-region: drag; + zoom: 1; /* prevent zooming */ +} + +.monaco-workbench > .part.titlebar, +.titlebar-style-custom .monaco-workbench.fullscreen > .part.titlebar { + height: 0; /* needs extra class to be enabled (also disabled in fullscreen mode) */ + display: none; +} + +.titlebar-style-custom .monaco-workbench > .part.titlebar { + height: 22px; + line-height: 22px; + display: flex; +} + +.monaco-workbench > .part.titlebar > .window-title { + flex: 0 1 auto; + overflow: hidden; + white-space: nowrap; + line-height: 22px; + text-overflow: ellipsis; + -webkit-app-region: drag; + zoom: 1; /* prevent zooming */ +} + +.titlebar-style-custom .monaco-workbench.fullscreen .quick-open-widget, +.titlebar-style-custom .global-message-list { + top: 0; +} + +.titlebar-style-custom .monaco-workbench .quick-open-widget, +.titlebar-style-custom .global-message-list { + top: 22px; /* push down quick open and messages when we have a custom title bar */ +} + +/* Theming */ + +.vs .monaco-workbench > .part.titlebar { + background: #ddd; + color: #333333; +} + +.vs-dark .monaco-workbench > .part.titlebar { + background: #3c3c3c; + color: #ccc; +} + +.hc-black .monaco-workbench > .part.titlebar { + background: #000; + color: white; +} \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts new file mode 100644 index 00000000000..842a8bcab42 --- /dev/null +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import 'vs/css!./media/titlebarpart'; +import { Builder, $, Dimension } from 'vs/base/browser/builder'; +import { Part } from 'vs/workbench/browser/part'; +import { ITitleService } from 'vs/workbench/services/title/common/titleService'; +import { getZoomFactor } from 'vs/base/browser/browser'; + +export class TitlebarPart extends Part implements ITitleService { + + public _serviceBrand: any; + + private titleContainer: Builder; + private title: Builder; + private pendingTitle: string; + private initialTitleFontSize: number; + + public createContentArea(parent: Builder): Builder { + this.titleContainer = $(parent); + + // Title + this.title = $(this.titleContainer).div({ class: 'window-title' }); + if (this.pendingTitle) { + this.title.text(this.pendingTitle); + } + + return this.titleContainer; + } + + public updateTitle(title: string): void { + + // Always set the native window title to identify us properly to the OS + window.document.title = title; + + // Apply if we can + if (this.title) { + this.title.text(title); + } else { + this.pendingTitle = title; + } + } + + public layout(dimension: Dimension): Dimension[] { + + // To prevent zooming we need to adjust the font size with the zoom factor + if (typeof this.initialTitleFontSize !== 'number') { + this.initialTitleFontSize = parseInt(this.titleContainer.getComputedStyle().fontSize, 10); + } + this.titleContainer.style({ fontSize: `${this.initialTitleFontSize / getZoomFactor()}px` }); + + return super.layout(dimension); + } +} \ No newline at end of file diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index 316e19103d2..2a45200232c 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -205,7 +205,7 @@ export abstract class EditorInput implements IEditorInput { * if the EditorModel should be refreshed before returning it. Depending on the implementation * this could mean to refresh the editor model contents with the version from disk. */ - public abstract resolve(refresh?: boolean): TPromise; + public abstract resolve(refresh?: boolean): TPromise; /** * An editor that is dirty will be asked to be saved once it closes. @@ -857,6 +857,7 @@ export interface IWorkbenchEditorConfiguration { workbench: { editor: { showTabs: boolean; + showTabCloseButton: boolean; showIcons: boolean; enablePreview: boolean; enablePreviewFromQuickOpen: boolean; diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index 923ad39e00b..0af33cf092b 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -5,21 +5,10 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import { sequence } from 'vs/base/common/async'; -import { EditorModel, EditorInput } from 'vs/workbench/common/editor'; -import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; -import { IModel } from 'vs/editor/common/editorCommon'; +import { EditorInput, ITextEditorModel } from 'vs/workbench/common/editor'; import URI from 'vs/base/common/uri'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { IDisposable } from 'vs/base/common/lifecycle'; - -/** - * - */ -export interface IResourceEditorContentProvider { - provideTextContent(resource: URI): TPromise; -} +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; +import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; /** * A read-only text editor input whos contents are made of the provided resource that points to an existing @@ -27,92 +16,6 @@ export interface IResourceEditorContentProvider { */ export class ResourceEditorInput extends EditorInput { - // --- registry logic - // todo@joh,ben this should maybe be a service that is in charge of loading/resolving a uri from a scheme - - private static loadingModels: { [uri: string]: TPromise } = Object.create(null); - private static registry: { [scheme: string]: IResourceEditorContentProvider[] } = Object.create(null); - - public static registerResourceContentProvider(scheme: string, provider: IResourceEditorContentProvider): IDisposable { - let array = ResourceEditorInput.registry[scheme]; - if (!array) { - array = [provider]; - ResourceEditorInput.registry[scheme] = array; - } else { - array.unshift(provider); - } - - return { - dispose() { - let array = ResourceEditorInput.registry[scheme]; - let idx = array.indexOf(provider); - if (idx >= 0) { - array.splice(idx, 1); - if (array.length === 0) { - delete ResourceEditorInput.registry[scheme]; - } - } - } - }; - } - - private static getOrCreateModel(modelService: IModelService, resource: URI): TPromise { - const model = modelService.getModel(resource); - if (model) { - return TPromise.as(model); - } - - let loadingModel = ResourceEditorInput.loadingModels[resource.toString()]; - if (!loadingModel) { - - // make sure we have a provider this scheme - // the resource uses - const array = ResourceEditorInput.registry[resource.scheme]; - if (!array) { - return TPromise.wrapError(`No model with uri '${resource}' nor a resolver for the scheme '${resource.scheme}'.`); - } - - // load the model-content from the provider and cache - // the loading such that we don't create the same model - // twice - ResourceEditorInput.loadingModels[resource.toString()] = loadingModel = new TPromise((resolve, reject) => { - let result: IModel; - let lastError: any; - - sequence(array.map(provider => { - return () => { - if (!result) { - const contentPromise = provider.provideTextContent(resource); - if (!contentPromise) { - return TPromise.wrapError(`No resolver for the scheme '${resource.scheme}' found.`); - } - - return contentPromise.then(value => { - result = value; - }, err => { - lastError = err; - }); - } - }; - })).then(() => { - if (!result && lastError) { - reject(lastError); - } else { - resolve(result); - } - }, reject); - - }, function () { - // no cancellation when caching promises - }); - - // remove the cached promise 'cos the model is now known to the model service (see above) - loadingModel.then(() => delete ResourceEditorInput.loadingModels[resource.toString()], () => delete ResourceEditorInput.loadingModels[resource.toString()]); - } - - return loadingModel; - } - public static ID: string = 'workbench.editors.resourceEditorInput'; protected cachedModel: ResourceEditorModel; @@ -125,8 +28,7 @@ export class ResourceEditorInput extends EditorInput { name: string, description: string, resource: URI, - @IModelService protected modelService: IModelService, - @IInstantiationService protected instantiationService: IInstantiationService + @ITextModelResolverService private textModelResolverService: ITextModelResolverService ) { super(); @@ -161,28 +63,28 @@ export class ResourceEditorInput extends EditorInput { } } - public resolve(refresh?: boolean): TPromise { + public resolve(refresh?: boolean): TPromise { // Use Cached Model if (this.cachedModel) { - return TPromise.as(this.cachedModel); + return TPromise.as(this.cachedModel); } // Otherwise Create Model and handle dispose event - return ResourceEditorInput.getOrCreateModel(this.modelService, this.resource).then(() => { - let model = this.instantiationService.createInstance(ResourceEditorModel, this.resource); + return this.textModelResolverService.resolve(this.resource).then(model => { + if (!(model instanceof ResourceEditorModel)) { + return TPromise.wrapError(`Unexpected model for ResourceInput: ${this.resource}`); // TODO@Ben eventually also files should be supported, but we guard due to the dangerous dispose of the model in dispose() + } + + this.cachedModel = model; + const unbind = model.onDispose(() => { this.cachedModel = null; // make sure we do not dispose model again unbind.dispose(); this.dispose(); }); - // Load it - return model.load().then((resolvedModel: ResourceEditorModel) => { - this.cachedModel = resolvedModel; - - return this.cachedModel; - }); + return this.cachedModel; }); } diff --git a/src/vs/workbench/electron-browser/actions.ts b/src/vs/workbench/electron-browser/actions.ts index c37f2a181ea..29c19a83d53 100644 --- a/src/vs/workbench/electron-browser/actions.ts +++ b/src/vs/workbench/electron-browser/actions.ts @@ -10,7 +10,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import timer = require('vs/base/common/timer'); import { Action } from 'vs/base/common/actions'; import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { EditorInput } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; @@ -28,14 +28,14 @@ import { IWorkspaceConfigurationService } from 'vs/workbench/services/configurat import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import paths = require('vs/base/common/paths'); import { isMacintosh } from 'vs/base/common/platform'; -import { IQuickOpenService, IPickOpenEntry, IFilePickOpenEntry, ISeparator } from 'vs/workbench/services/quickopen/common/quickOpenService'; +import { IQuickOpenService, IFilePickOpenEntry, ISeparator } from 'vs/workbench/services/quickopen/common/quickOpenService'; import { KeyMod } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import * as browser from 'vs/base/browser/browser'; import { IIntegrityService } from 'vs/platform/integrity/common/integrity'; import * as os from 'os'; -import { ipcRenderer as ipc, webFrame, remote } from 'electron'; +import { webFrame, remote } from 'electron'; // --- actions @@ -80,129 +80,117 @@ export class CloseWindowAction extends Action { export class SwitchWindow extends Action { - public static ID = 'workbench.action.switchWindow'; - public static LABEL = nls.localize('switchWindow', "Switch Window"); + static ID = 'workbench.action.switchWindow'; + static LABEL = nls.localize('switchWindow', "Switch Window"); constructor( id: string, label: string, - @IWindowIPCService private windowService: IWindowIPCService, + @IWindowsService private windowsService: IWindowsService, + @IWindowService private windowService: IWindowService, @IQuickOpenService private quickOpenService: IQuickOpenService ) { super(id, label); } - public run(): TPromise { - const id = this.windowService.getWindowId(); - ipc.send('vscode:switchWindow', id); - ipc.once('vscode:switchWindow', (event, workspaces) => { - const picks: IPickOpenEntry[] = workspaces.map(w => { - return { - label: w.title, - description: (id === w.id) ? nls.localize('current', "Current Window") : void 0, - run: () => { - ipc.send('vscode:showWindow', w.id); - } - }; - }); - this.quickOpenService.pick(picks, { placeHolder: nls.localize('switchWindowPlaceHolder', "Select a window") }); - }); + run(): TPromise { + const currentWindowId = this.windowService.getCurrentWindowId(); - return TPromise.as(true); + return this.windowsService.getWindows().then(workspaces => { + const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window"); + const picks = workspaces.map(w => ({ + label: w.title, + description: (currentWindowId === w.id) ? nls.localize('current', "Current Window") : void 0, + run: () => this.windowsService.showWindow(w.id) + })); + + this.quickOpenService.pick(picks, { placeHolder }); + }); } } export class CloseFolderAction extends Action { - public static ID = 'workbench.action.closeFolder'; - public static LABEL = nls.localize('closeFolder', "Close Folder"); + static ID = 'workbench.action.closeFolder'; + static LABEL = nls.localize('closeFolder', "Close Folder"); constructor( id: string, label: string, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IMessageService private messageService: IMessageService, - @IWindowIPCService private windowService: IWindowIPCService + @IWindowService private windowService: IWindowService ) { super(id, label); } - public run(): TPromise { - if (this.contextService.getWorkspace()) { - ipc.send('vscode:closeFolder', this.windowService.getWindowId()); // handled from browser process - } else { + run(): TPromise { + if (!this.contextService.getWorkspace()) { this.messageService.show(Severity.Info, nls.localize('noFolderOpened', "There is currently no folder opened in this instance to close.")); + return TPromise.as(null); } - return TPromise.as(true); + return this.windowService.closeFolder(); } } export class NewWindowAction extends Action { - public static ID = 'workbench.action.newWindow'; - public static LABEL = nls.localize('newWindow', "New Window"); + static ID = 'workbench.action.newWindow'; + static LABEL = nls.localize('newWindow', "New Window"); constructor( id: string, label: string, - @IWindowIPCService private windowService: IWindowIPCService + @IWindowsService private windowsService: IWindowsService ) { super(id, label); } - public run(): TPromise { - this.windowService.getWindow().openNew(); - - return TPromise.as(true); + run(): TPromise { + return this.windowsService.openNewWindow(); } } export class ToggleFullScreenAction extends Action { - public static ID = 'workbench.action.toggleFullScreen'; - public static LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen"); + static ID = 'workbench.action.toggleFullScreen'; + static LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen"); - constructor(id: string, label: string, @IWindowIPCService private windowService: IWindowIPCService) { + constructor(id: string, label: string, @IWindowService private windowService: IWindowService) { super(id, label); } - public run(): TPromise { - ipc.send('vscode:toggleFullScreen', this.windowService.getWindowId()); - - return TPromise.as(true); + run(): TPromise { + return this.windowService.toggleFullScreen(); } } export class ToggleMenuBarAction extends Action { - public static ID = 'workbench.action.toggleMenuBar'; - public static LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar"); + static ID = 'workbench.action.toggleMenuBar'; + static LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar"); - constructor(id: string, label: string, @IWindowIPCService private windowService: IWindowIPCService) { + constructor(id: string, label: string, @IWindowService private windowService: IWindowService) { super(id, label); } - public run(): TPromise { - ipc.send('vscode:toggleMenuBar', this.windowService.getWindowId()); - - return TPromise.as(true); + run(): TPromise { + return this.windowService.toggleMenuBar(); } } export class ToggleDevToolsAction extends Action { - public static ID = 'workbench.action.toggleDevTools'; - public static LABEL = nls.localize('toggleDevTools', "Toggle Developer Tools"); + static ID = 'workbench.action.toggleDevTools'; + static LABEL = nls.localize('toggleDevTools', "Toggle Developer Tools"); - constructor(id: string, label: string, @IWindowIPCService private windowService: IWindowIPCService) { + constructor(id: string, label: string, @IWindowService private windowsService: IWindowService) { super(id, label); } - public run(): TPromise { - ipc.send('vscode:toggleDevTools', this.windowService.getWindowId()); - - return TPromise.as(true); + public run(): TPromise { + return this.windowsService.toggleDevTools(); } } @@ -228,6 +216,7 @@ export abstract class BaseZoomAction extends Action { const applyZoom = () => { webFrame.setZoomLevel(level); browser.setZoomLevel(level); // Ensure others can listen to zoom level changes + browser.setZoomFactor(webFrame.getZoomFactor()); }; this.configurationEditingService.writeConfiguration(target, { key: BaseZoomAction.SETTING_KEY, value: level }).done(() => applyZoom(), error => applyZoom()); @@ -330,7 +319,7 @@ export class ShowStartupPerformance extends Action { constructor( id: string, label: string, - @IWindowIPCService private windowService: IWindowIPCService, + @IWindowService private windowService: IWindowService, @IEnvironmentService environmentService: IEnvironmentService ) { super(id, label); @@ -405,9 +394,8 @@ export class ShowStartupPerformance extends Action { sum['Took (ms)'] = lastEvent.stopTime.getTime() - start; table.push(sum); - // Show dev tools - this.windowService.getWindow().openDevTools(); + this.windowService.openDevTools(); // Print to console setTimeout(() => { @@ -447,23 +435,17 @@ export class OpenRecentAction extends Action { constructor( id: string, label: string, - @IWindowIPCService private windowService: IWindowIPCService, + @IWindowsService private windowsService: IWindowsService, + @IWindowService private windowService: IWindowService, @IQuickOpenService private quickOpenService: IQuickOpenService, @IWorkspaceContextService private contextService: IWorkspaceContextService ) { super(id, label); } - public run(): TPromise { - ipc.send('vscode:openRecent', this.windowService.getWindowId()); - - return new TPromise((c, e, p) => { - ipc.once('vscode:openRecent', (event, files: string[], folders: string[]) => { - this.openRecent(files, folders); - - c(true); - }); - }); + public run(): TPromise { + return this.windowService.getRecentlyOpen() + .then(({ files, folders }) => this.openRecent(files, folders)); } private openRecent(recentFiles: string[], recentFolders: string[]): void { @@ -478,11 +460,10 @@ export class OpenRecentAction extends Action { }; } - function runPick(path: string, context): void { + const runPick = (path: string, context) => { const newWindow = context.keymods.indexOf(KeyMod.CtrlCmd) >= 0; - - ipc.send('vscode:windowOpen', [path], newWindow); - } + this.windowsService.windowOpen([path], newWindow); + }; const folderPicks: IFilePickOpenEntry[] = recentFolders.map((p, index) => toPick(p, index === 0 ? { label: nls.localize('folders', "folders") } : void 0, true)); const filePicks: IFilePickOpenEntry[] = recentFiles.map((p, index) => toPick(p, index === 0 ? { label: nls.localize('files', "files"), border: true } : void 0, false)); @@ -589,14 +570,6 @@ Steps to Reproduce: // --- commands -CommandsRegistry.registerCommand('_workbench.ipc', function (accessor: ServicesAccessor, ipcMessage: string, ipcArgs: any[]) { - if (ipcMessage && Array.isArray(ipcArgs)) { - ipc.send(ipcMessage, ...ipcArgs); - } else { - ipc.send(ipcMessage); - } -}); - CommandsRegistry.registerCommand('_workbench.diff', function (accessor: ServicesAccessor, args: [URI, URI, string]) { const editorService = accessor.get(IWorkbenchEditorService); let [left, right, label] = args; diff --git a/src/vs/workbench/electron-browser/bootstrap/index.js b/src/vs/workbench/electron-browser/bootstrap/index.js index 7c66ad35cf6..f8b8a813334 100644 --- a/src/vs/workbench/electron-browser/bootstrap/index.js +++ b/src/vs/workbench/electron-browser/bootstrap/index.js @@ -13,11 +13,10 @@ const path = require('path'); const electron = require('electron'); const remote = electron.remote; const ipc = electron.ipcRenderer; -const windowId = remote.getCurrentWindow().id; function onError(error, enableDeveloperTools) { if (enableDeveloperTools) { - ipc.send('vscode:openDevTools', windowId); + remote.getCurrentWebContents().openDevTools(); } console.error('[uncaught exception]: ' + error); @@ -63,6 +62,7 @@ function uriFromPath(_path) { function registerListeners(enableDeveloperTools) { // Devtools & reload support + var listener; if (enableDeveloperTools) { const extractKey = function (e) { return [ @@ -77,18 +77,25 @@ function registerListeners(enableDeveloperTools) { const TOGGLE_DEV_TOOLS_KB = (process.platform === 'darwin' ? 'meta-alt-73' : 'ctrl-shift-73'); // mac: Cmd-Alt-I, rest: Ctrl-Shift-I const RELOAD_KB = (process.platform === 'darwin' ? 'meta-82' : 'ctrl-82'); // mac: Cmd-R, rest: Ctrl-R - window.addEventListener('keydown', function (e) { + listener = function (e) { const key = extractKey(e); if (key === TOGGLE_DEV_TOOLS_KB) { - ipc.send('vscode:toggleDevTools', windowId); - // remote.getCurrentWebContents().toggleDevTools(); + remote.getCurrentWebContents().toggleDevTools(); } else if (key === RELOAD_KB) { remote.getCurrentWindow().reload(); } - }); + }; + window.addEventListener('keydown', listener); } process.on('uncaughtException', function (error) { onError(error, enableDeveloperTools) }); + + return function () { + if (listener) { + window.removeEventListener('keydown', listener); + listener = void 0; + } + } } function main() { @@ -119,7 +126,7 @@ function main() { window.document.documentElement.setAttribute('lang', locale); const enableDeveloperTools = process.env['VSCODE_DEV'] || !!configuration.extensionDevelopmentPath; - registerListeners(enableDeveloperTools); + const unbind = registerListeners(enableDeveloperTools); // disable pinch zoom & apply zoom level early to avoid glitches const zoomLevel = configuration.zoomLevel; @@ -171,7 +178,11 @@ function main() { require('vs/workbench/electron-browser/main') .startup(configuration) - .done(null, function (error) { onError(error, enableDeveloperTools); }); + .done(function () { + unbind(); // since the workbench is running, unbind our developer related listeners and let the workbench handle them + }, function (error) { + onError(error, enableDeveloperTools); + }); }); }); } diff --git a/src/vs/workbench/electron-browser/common.ts b/src/vs/workbench/electron-browser/common.ts index 605aeefb9cb..6b2843f0559 100644 --- a/src/vs/workbench/electron-browser/common.ts +++ b/src/vs/workbench/electron-browser/common.ts @@ -23,5 +23,6 @@ export interface IWindowConfiguration { reopenFolders: string; restoreFullscreen: boolean; zoomLevel: number; + titleBarStyle: 'native' | 'custom'; }; } \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/crashReporter.ts b/src/vs/workbench/electron-browser/crashReporter.ts index ab43c0b01c1..615df4f6e1c 100644 --- a/src/vs/workbench/electron-browser/crashReporter.ts +++ b/src/vs/workbench/electron-browser/crashReporter.ts @@ -5,17 +5,23 @@ 'use strict'; import nls = require('vs/nls'); -import { TPromise } from 'vs/base/common/winjs.base'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { assign, clone } from 'vs/base/common/objects'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ITelemetryService, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Registry } from 'vs/platform/platform'; - -import { ipcRenderer as ipc, crashReporter } from 'electron'; +import { crashReporter } from 'electron'; +import product from 'vs/platform/product'; +import pkg from 'vs/platform/package'; const TELEMETRY_SECTION_ID = 'telemetry'; +interface ICrashReporterConfig { + enableCrashReporter: boolean; +} + const configurationRegistry = Registry.as(Extensions.Configuration); configurationRegistry.registerConfiguration({ 'id': TELEMETRY_SECTION_ID, @@ -31,71 +37,29 @@ configurationRegistry.registerConfiguration({ }); export class CrashReporter { - private isStarted: boolean; - private config: any; - private version: string; - private commit: string; - private sessionId: string; - constructor(version: string, commit: string, - @ITelemetryService private telemetryService: ITelemetryService = NullTelemetryService, - @IConfigurationService private configurationService: IConfigurationService + constructor( + configuration: Electron.CrashReporterStartOptions, + @ITelemetryService telemetryService: ITelemetryService, + @IWindowsService windowsService: IWindowsService, + @IConfigurationService configurationService: IConfigurationService ) { - this.configurationService = configurationService; - this.telemetryService = telemetryService; - this.version = version; - this.commit = commit; + const config = configurationService.getConfiguration(TELEMETRY_SECTION_ID); - this.isStarted = false; - this.config = null; - } - - public start(rawConfiguration: Electron.CrashReporterStartOptions): void { - if (!this.isStarted) { - - const sessionId = !this.sessionId - ? this.telemetryService.getTelemetryInfo().then(info => this.sessionId = info.sessionId) - : TPromise.as(undefined); - - sessionId.then(() => { - if (!this.config) { - this.config = this.configurationService.getConfiguration(TELEMETRY_SECTION_ID); - if (this.config && this.config.enableCrashReporter) { - this.doStart(rawConfiguration); - } - } else { - if (this.config.enableCrashReporter) { - this.doStart(rawConfiguration); - } - } - }, onUnexpectedError); + if (!config.enableCrashReporter) { + return; } - } - private doStart(rawConfiguration: Electron.CrashReporterStartOptions): void { - const config = this.toConfiguration(rawConfiguration); + telemetryService.getTelemetryInfo() + .then(info => ({ vscode_sessionId: info.sessionId, vscode_version: pkg.version, vscode_commit: product.commit })) + .then(extra => assign(configuration, { extra })) + .then(configuration => { + // start crash reporter right here + crashReporter.start(clone(configuration)); - crashReporter.start(config); - - //notify the main process to start the crash reporter - ipc.send('vscode:startCrashReporter', config); - } - - private toConfiguration(rawConfiguration: Electron.CrashReporterStartOptions): Electron.CrashReporterStartOptions { - return JSON.parse(JSON.stringify(rawConfiguration, (key, value) => { - if (value === '$(sessionId)') { - return this.sessionId; - } - - if (value === '$(version)') { - return this.version; - } - - if (value === '$(commit)') { - return this.commit; - } - - return value; - })); + // TODO: start crash reporter in the main process + return windowsService.startCrashReporter(configuration); + }) + .done(null, onUnexpectedError); } } \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/extensionHost.ts b/src/vs/workbench/electron-browser/extensionHost.ts index d48a8687bc8..33fde5a40ce 100644 --- a/src/vs/workbench/electron-browser/extensionHost.ts +++ b/src/vs/workbench/electron-browser/extensionHost.ts @@ -15,6 +15,7 @@ import { isWindows } from 'vs/base/common/platform'; import { findFreePort } from 'vs/base/node/ports'; import { IMessageService, Severity } from 'vs/platform/message/common/message'; import { ILifecycleService, ShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; @@ -27,9 +28,9 @@ import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import Event, { Emitter } from 'vs/base/common/event'; import { WatchDog } from 'vs/base/common/watchDog'; import { createQueuedSender, IQueuedSender } from 'vs/base/node/processes'; -import { IInitData, IInitConfiguration } from 'vs/workbench/api/node/extHost.protocol'; +import { IInitData } from 'vs/workbench/api/node/extHost.protocol'; import { MainProcessExtensionService } from 'vs/workbench/api/node/mainThreadExtensionService'; -import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkspaceConfigurationService, getWorkspaceConfigurationTree } from 'vs/workbench/services/configuration/common/configuration'; export const EXTENSION_LOG_BROADCAST_CHANNEL = 'vscode:extensionLog'; export const EXTENSION_ATTACH_BROADCAST_CHANNEL = 'vscode:extensionAttach'; @@ -68,6 +69,7 @@ export class ExtensionHostProcessWorker { constructor( @IWorkspaceContextService private contextService: IWorkspaceContextService, @IMessageService private messageService: IMessageService, + @IWindowsService private windowsService: IWindowsService, @IWindowIPCService private windowService: IWindowIPCService, @ILifecycleService lifecycleService: ILifecycleService, @IInstantiationService private instantiationService: IInstantiationService, @@ -131,7 +133,7 @@ export class ExtensionHostProcessWorker { ids.push(ext.id); } } - this.telemetryService.publicLog('extHostUnresponsive', ids); + this.telemetryService.publicLog('extHostUnresponsive', { extensionIds: ids }); }); }); }); @@ -256,7 +258,7 @@ export class ExtensionHostProcessWorker { workspace: this.contextService.getWorkspace() }, extensions: extensionDescriptions, - configuration: this.configurationService.getConfiguration(), + configuration: getWorkspaceConfigurationTree(this.configurationService), telemetryInfo }; this.extensionHostProcessQueuedSender.send(stringify(initData)); @@ -289,7 +291,7 @@ export class ExtensionHostProcessWorker { // Log on main side if running tests from cli if (this.isExtensionDevelopmentTestFromCli) { - ipc.send('vscode:log', logEntry); + this.windowsService.log(logEntry.severity, ...args); } // Broadcast to other windows if we are in development mode diff --git a/src/vs/workbench/electron-browser/integration.ts b/src/vs/workbench/electron-browser/integration.ts index ed76f6de9de..8ae09d797cc 100644 --- a/src/vs/workbench/electron-browser/integration.ts +++ b/src/vs/workbench/electron-browser/integration.ts @@ -6,7 +6,10 @@ 'use strict'; import nls = require('vs/nls'); +import { Registry } from 'vs/platform/platform'; import { TPromise } from 'vs/base/common/winjs.base'; +import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import errors = require('vs/base/common/errors'); import types = require('vs/base/common/types'); import arrays = require('vs/base/common/arrays'); @@ -34,8 +37,10 @@ import { IPath, IOpenFileRequest, IWindowConfiguration } from 'vs/workbench/elec import { IResourceInput } from 'vs/platform/editor/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import URI from 'vs/base/common/uri'; +import { ReloadWindowAction, ToggleDevToolsAction, ShowStartupPerformance } from 'vs/workbench/electron-browser/actions'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ipcRenderer as ipc, webFrame, remote } from 'electron'; @@ -69,8 +74,8 @@ export class ElectronIntegration { @IMessageService private messageService: IMessageService, @IContextMenuService private contextMenuService: IContextMenuService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IExtensionGalleryService private extensionGalleryService: IExtensionGalleryService, - @IUntitledEditorService private untitledEditorService: IUntitledEditorService + @IUntitledEditorService private untitledEditorService: IUntitledEditorService, + @IEnvironmentService private environmentService: IEnvironmentService ) { } @@ -136,18 +141,23 @@ export class ElectronIntegration { ipc.on('vscode:enterFullScreen', (event) => { this.partService.joinCreation().then(() => { this.partService.addClass('fullscreen'); + + if (!this.partService.isTitleBarHidden()) { + this.partService.layout({ forceStyleRecompute: true }); // handle title bar when fullscreen changes + } }); }); ipc.on('vscode:leaveFullScreen', (event) => { this.partService.joinCreation().then(() => { this.partService.removeClass('fullscreen'); + + if (!this.partService.isTitleBarHidden()) { + this.partService.layout({ forceStyleRecompute: true }); // handle title bar when fullscreen changes + } }); }); - // Ensure others can listen to zoom level changes - browser.setZoomLevel(webFrame.getZoomLevel()); - // Configuration changes let previousConfiguredZoomLevel: number; this.configurationService.onDidUpdateConfiguration(e => { @@ -168,6 +178,7 @@ export class ElectronIntegration { if (webFrame.getZoomLevel() !== newZoomLevel) { webFrame.setZoomLevel(newZoomLevel); browser.setZoomLevel(webFrame.getZoomLevel()); // Ensure others can listen to zoom level changes + browser.setZoomFactor(webFrame.getZoomFactor()); } }); @@ -195,12 +206,15 @@ export class ElectronIntegration { } }); - // Extra request headers - this.extensionGalleryService.getRequestHeaders().done(headers => { - const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*']; - - ipc.send('vscode:setHeaders', this.windowService.getWindowId(), urls, headers); - }); + // Developer related actions + const developerCategory = nls.localize('developer', "Developer"); + const workbenchActionsRegistry = Registry.as(Extensions.WorkbenchActions); + const isDeveloping = !this.environmentService.isBuilt || !!this.environmentService.extensionDevelopmentPath; + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyCode.KEY_R } : void 0), 'Reload Window'); + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL, isDeveloping ? { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_I, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_I } } : void 0), 'Developer: Toggle Developer Tools', developerCategory); + if (this.environmentService.performance) { + workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowStartupPerformance, ShowStartupPerformance.ID, ShowStartupPerformance.LABEL), 'Developer: Startup Performance', developerCategory); + } } private resolveKeybindings(actionIds: string[]): TPromise<{ id: string; binding: number; }[]> { diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index 5334588791d..578fc6f0ccc 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -16,15 +16,15 @@ import platform = require('vs/base/common/platform'); import { IKeybindings } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; -import { CloseEditorAction, ReloadWindowAction, ShowStartupPerformance, ReportIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleDevToolsAction, ToggleFullScreenAction, ToggleMenuBarAction, OpenRecentAction, CloseFolderAction, CloseWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction } from 'vs/workbench/electron-browser/actions'; +import { CloseEditorAction, ReportIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, OpenRecentAction, CloseFolderAction, CloseWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction } from 'vs/workbench/electron-browser/actions'; import { MessagesVisibleContext, NoEditorsVisibleContext } from 'vs/workbench/electron-browser/workbench'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; const closeEditorOrWindowKeybindings: IKeybindings = { primary: KeyMod.CtrlCmd | KeyCode.KEY_W, win: { primary: KeyMod.CtrlCmd | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_W] } }; // Contribute Global Actions const viewCategory = nls.localize('view', "View"); const helpCategory = nls.localize('help', "Help"); -const developerCategory = nls.localize('developer', "Developer"); const fileCategory = nls.localize('file', "File"); const workbenchActionsRegistry = Registry.as(Extensions.WorkbenchActions); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NewWindowAction, NewWindowAction.ID, NewWindowAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_N }), 'New Window'); @@ -32,7 +32,6 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseW workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SwitchWindow, SwitchWindow.ID, SwitchWindow.LABEL), 'Switch Window'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseFolderAction, CloseFolderAction.ID, CloseFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Folder', fileCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent', fileCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL), 'Developer: Toggle Developer Tools', developerCategory); if (!!product.reportIssueUrl) { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReportIssueAction, ReportIssueAction.ID, ReportIssueAction.LABEL), 'Help: Report Issues', helpCategory); } @@ -45,8 +44,6 @@ workbenchActionsRegistry.registerWorkbenchAction( }), 'View: Zoom Out', viewCategory ); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ZoomResetAction, ZoomResetAction.ID, ZoomResetAction.LABEL), 'View: Reset Zoom', viewCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ShowStartupPerformance, ShowStartupPerformance.ID, ShowStartupPerformance.LABEL), 'Developer: Startup Performance', developerCategory); -workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL), 'Reload Window'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseMessagesAction, CloseMessagesAction.ID, CloseMessagesAction.LABEL, { primary: KeyCode.Escape, secondary: [KeyMod.Shift | KeyCode.Escape] }, MessagesVisibleContext), 'Close Notification Messages'); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(CloseEditorAction, CloseEditorAction.ID, CloseEditorAction.LABEL, closeEditorOrWindowKeybindings), 'View: Close Editor', viewCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory); @@ -79,6 +76,11 @@ configurationRegistry.registerConfiguration({ 'description': nls.localize('showEditorTabs', "Controls if opened editors should show in tabs or not."), 'default': true }, + 'workbench.editor.showTabCloseButton': { + 'type': 'boolean', + 'description': nls.localize('showEditorTabCloseButton', "Controls if editor tabs should have a visible close button or not."), + 'default': true + }, 'workbench.editor.showIcons': { 'type': 'boolean', 'description': nls.localize('showIcons', "Controls if opened editors should show with an icon or not. This requires an icon theme to be enabled as well."), @@ -130,37 +132,48 @@ configurationRegistry.registerConfiguration({ }); // Configuration: Window +let properties: { [path: string]: IJSONSchema; } = { + 'window.openFilesInNewWindow': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('openFilesInNewWindow', "When enabled, will open files in a new window instead of reusing an existing instance.") + }, + 'window.reopenFolders': { + 'type': 'string', + 'enum': ['none', 'one', 'all'], + 'default': 'one', + 'description': nls.localize('reopenFolders', "Controls how folders are being reopened after a restart. Select 'none' to never reopen a folder, 'one' to reopen the last folder you worked on or 'all' to reopen all folders of your last session.") + }, + 'window.restoreFullscreen': { + 'type': 'boolean', + 'default': false, + 'description': nls.localize('restoreFullscreen', "Controls if a window should restore to full screen mode if it was exited in full screen mode.") + }, + 'window.zoomLevel': { + 'type': 'number', + 'default': 0, + 'description': nls.localize('zoomLevel', "Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1) or below (e.g. -1) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity.") + }, + 'window.showFullPath': { + 'type': 'boolean', + 'default': false, + 'description': nls.localize('showFullPath', "If enabled, will show the full path of opened files in the window title.") + } +}; + +if (platform.isMacintosh) { + properties['window.titleBarStyle'] = { + 'type': 'string', + 'enum': ['native', 'custom'], + 'default': 'custom', + 'description': nls.localize('titleBarStyle', "Adjust the appearance of the window title bar. Changes require a full restart to apply.") + }; +} + configurationRegistry.registerConfiguration({ 'id': 'window', 'order': 8, 'title': nls.localize('windowConfigurationTitle', "Window"), 'type': 'object', - 'properties': { - 'window.openFilesInNewWindow': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('openFilesInNewWindow', "When enabled, will open files in a new window instead of reusing an existing instance.") - }, - 'window.reopenFolders': { - 'type': 'string', - 'enum': ['none', 'one', 'all'], - 'default': 'one', - 'description': nls.localize('reopenFolders', "Controls how folders are being reopened after a restart. Select 'none' to never reopen a folder, 'one' to reopen the last folder you worked on or 'all' to reopen all folders of your last session.") - }, - 'window.restoreFullscreen': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('restoreFullscreen', "Controls if a window should restore to full screen mode if it was exited in full screen mode.") - }, - 'window.zoomLevel': { - 'type': 'number', - 'default': 0, - 'description': nls.localize('zoomLevel', "Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1) or below (e.g. -1) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity.") - }, - 'window.showFullPath': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('showFullPath', "If enabled, will show the full path of opened files in the window title.") - } - } + 'properties': properties }); \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/media/workbench.css b/src/vs/workbench/electron-browser/media/workbench.css index 3b12ab0ab25..439f4e6fa57 100644 --- a/src/vs/workbench/electron-browser/media/workbench.css +++ b/src/vs/workbench/electron-browser/media/workbench.css @@ -46,20 +46,6 @@ z-index: 10000; } -.vs #monaco-workbench-drop-overlay { - background-color: rgba(51,153,255, 0.18); -} - -.vs-dark #monaco-workbench-drop-overlay { - background-color: rgba(83, 89, 93, 0.5); -} - -.hc-black #monaco-workbench-drop-overlay { - background: none !important; - outline: 2px dashed #f38518; - outline-offset: -2px; -} - /* ---------- Light Theme ---------- */ .vs .monaco-workbench { background-color: #F3F3F3; } @@ -74,6 +60,10 @@ background-color: #E1E1E1; } +.vs #monaco-workbench-drop-overlay { + background-color: rgba(51,153,255, 0.18); +} + /* ---------- Dark Theme ---------- */ .vs-dark .monaco-workbench { @@ -104,6 +94,10 @@ .vs-dark .monaco-workbench .stacked-view .action-label { color: inherit; } .vs-dark .monaco-workbench .stacked-view .action-label:hover { color: #3399FF; } +.vs-dark #monaco-workbench-drop-overlay { + background-color: rgba(83, 89, 93, 0.5); +} + /* ---------- HC Theme ---------- */ .hc-black .monaco-workbench { color: #FFF; background-color: #000; } @@ -123,3 +117,9 @@ .hc-black .monaco-workbench .monaco-action-bar .action-item.disabled .action-label.disabled { opacity: .4; } + +.hc-black #monaco-workbench-drop-overlay { + background: none !important; + outline: 2px dashed #f38518; + outline-offset: -2px; +} \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 2028336d7f5..b1e1995e429 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -18,6 +18,7 @@ import errors = require('vs/base/common/errors'); import { toErrorMessage } from 'vs/base/common/errorMessage'; import product from 'vs/platform/product'; import pkg from 'vs/platform/package'; +import * as browser from 'vs/base/browser/browser'; import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; import timer = require('vs/base/common/timer'); import { Workbench } from 'vs/workbench/electron-browser/workbench'; @@ -86,7 +87,7 @@ import { IURLService } from 'vs/platform/url/common/url'; import { ReloadWindowAction } from 'vs/workbench/electron-browser/actions'; import { WorkspaceConfigurationService } from 'vs/workbench/services/configuration/node/configurationService'; import { ExtensionHostProcessWorker } from 'vs/workbench/electron-browser/extensionHost'; -import { remote } from 'electron'; +import { remote, webFrame } from 'electron'; // self registering services import 'vs/platform/opener/browser/opener.contribution'; @@ -156,12 +157,11 @@ export class WorkbenchShell { //crash reporting if (!!product.crashReporter) { - const crashReporter = instantiationService.createInstance(CrashReporter, pkg.version, product.commit); - crashReporter.start(product.crashReporter); + instantiationService.createInstance(CrashReporter, product.crashReporter); } // Workbench - this.workbench = instantiationService.createInstance(Workbench, workbenchContainer.getHTMLElement(), this.workspace, this.options, serviceCollection); + this.workbench = instantiationService.createInstance(Workbench, parent.getHTMLElement(), workbenchContainer.getHTMLElement(), this.workspace, this.options, serviceCollection); this.workbench.startup({ onWorkbenchStarted: (customKeybindingsCount) => { this.onWorkbenchStarted(customKeybindingsCount); @@ -212,7 +212,7 @@ export class WorkbenchShell { } } - private initServiceCollection(container: HTMLElement): [InstantiationService, ServiceCollection] { + private initServiceCollection(container: HTMLElement): [IInstantiationService, ServiceCollection] { const disposables = new Disposables(); const mainProcessClient = new ElectronIPCClient(String(`window${remote.getCurrentWindow().id}`)); @@ -365,6 +365,10 @@ export class WorkbenchShell { this.onUnexpectedError(error); }); + // Ensure others can listen to zoom level changes + browser.setZoomLevel(webFrame.getZoomLevel()); + browser.setZoomFactor(webFrame.getZoomFactor()); + // Shell Class for CSS Scoping $(this.container).addClass('monaco-shell'); diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 13d0d826f5d..5c8eb52dd02 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -16,8 +16,9 @@ import { IPartService } from 'vs/workbench/services/part/common/partService'; import { asFileEditorInput } from 'vs/workbench/common/editor'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; -import { ipcRenderer as ipc, remote } from 'electron'; +import { remote } from 'electron'; const dialog = remote.dialog; @@ -30,7 +31,9 @@ export class ElectronWindow { shellContainer: HTMLElement, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IEditorGroupService private editorGroupService: IEditorGroupService, - @IPartService private partService: IPartService + @IPartService private partService: IPartService, + @IWindowsService private windowsService: IWindowsService, + @IWindowService private windowService: IWindowService ) { this.win = win; this.windowId = win.id; @@ -43,12 +46,9 @@ export class ElectronWindow { if (platform.platform === platform.Platform.Mac) { this.editorGroupService.onEditorsChanged(() => { const fileInput = asFileEditorInput(this.editorService.getActiveEditorInput(), true); - let representedFilename = ''; - if (fileInput) { - representedFilename = fileInput.getResource().fsPath; - } + const fileName = fileInput ? fileInput.getResource().fsPath : ''; - ipc.send('vscode:setRepresentedFilename', this.windowId, representedFilename); + this.windowService.setRepresentedFilename(fileName); }); } @@ -80,7 +80,7 @@ export class ElectronWindow { DOM.EventHelper.stop(e, true); this.focus(); // make sure this window has focus so that the open call reaches the right window! - ipc.send('vscode:windowOpen', draggedExternalResources.map(r => r.fsPath)); // handled from browser process + this.windowsService.windowOpen(draggedExternalResources.map(r => r.fsPath)); cleanUp(); }) @@ -119,18 +119,10 @@ export class ElectronWindow { }); // Handle window.open() calls - (window).open = function (url: string, target: string, features: string, replace: boolean) { - $this.openExternal(url); - - return null; - }; - - // Patch focus to also focus the entire window - const originalFocus = window.focus; const $this = this; - window.focus = function () { - originalFocus.call(this, arguments); - $this.focus(); + (window).open = function (url: string, target: string, features: string, replace: boolean) { + $this.windowsService.openExternal(url); + return null; }; } @@ -140,19 +132,10 @@ export class ElectronWindow { })).then(res => res.some(res => !!res)); } - public openNew(): void { - ipc.send('vscode:openNewWindow'); // handled from browser process - } - public close(): void { this.win.close(); } - public reload(): void { - this.partService.setRestoreSidebar(); // we want the same sidebar after a reload restored - ipc.send('vscode:reloadWindow', this.windowId); - } - public showMessageBox(options: Electron.ShowMessageBoxOptions): number { return dialog.showMessageBox(this.win, options); } @@ -165,31 +148,7 @@ export class ElectronWindow { return dialog.showSaveDialog(this.win, options); // https://github.com/electron/electron/issues/4936 } - public setFullScreen(fullscreen: boolean): void { - ipc.send('vscode:setFullScreen', this.windowId, fullscreen); // handled from browser process - } - - public openDevTools(): void { - ipc.send('vscode:openDevTools', this.windowId); // handled from browser process - } - - public setMenuBarVisibility(visible: boolean): void { - ipc.send('vscode:setMenuBarVisibility', this.windowId, visible); // handled from browser process - } - - public focus(): void { - ipc.send('vscode:focusWindow', this.windowId); // handled from browser process - } - - public flashFrame(): void { - ipc.send('vscode:flashFrame', this.windowId); // handled from browser process - } - - public showItemInFolder(path: string): void { - ipc.send('vscode:showItemInFolder', path); // handled from browser process to prevent foreground ordering issues on Windows - } - - public openExternal(url: string): void { - ipc.send('vscode:openExternal', url); // handled from browser process to prevent foreground ordering issues on Windows + public focus(): TPromise { + return this.windowService.focusWindow(); } } \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index ecd0b6c9eca..15e6604d619 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -11,14 +11,14 @@ import { TPromise, ValueCallback } from 'vs/base/common/winjs.base'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import strings = require('vs/base/common/strings'); import DOM = require('vs/base/browser/dom'); -import { Box, Builder, $ } from 'vs/base/browser/builder'; +import { Builder, $ } from 'vs/base/browser/builder'; import { Delayer } from 'vs/base/common/async'; import assert = require('vs/base/common/assert'); import timer = require('vs/base/common/timer'); import errors = require('vs/base/common/errors'); import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Registry } from 'vs/platform/platform'; -import { isWindows, isLinux } from 'vs/base/common/platform'; +import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; import { IOptions } from 'vs/workbench/common/options'; import { Position as EditorPosition } from 'vs/platform/editor/common/editor'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; @@ -30,7 +30,8 @@ import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart'; import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart'; import { StatusbarPart } from 'vs/workbench/browser/parts/statusbar/statusbarPart'; -import { WorkbenchLayout, LayoutOptions } from 'vs/workbench/browser/layout'; +import { TitlebarPart } from 'vs/workbench/browser/parts/titlebar/titlebarPart'; +import { WorkbenchLayout } from 'vs/workbench/browser/layout'; import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actionBarRegistry'; import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet'; import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; @@ -39,7 +40,7 @@ import { DiffEditorInput, toDiffLabel } from 'vs/workbench/common/editor/diffEdi import { getServices } from 'vs/platform/instantiation/common/extensions'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { WorkbenchEditorService } from 'vs/workbench/services/editor/browser/editorService'; -import { Position, Parts, IPartService } from 'vs/workbench/services/part/common/partService'; +import { Position, Parts, IPartService, ILayoutOptions } from 'vs/workbench/services/part/common/partService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ContextMenuService } from 'vs/workbench/services/contextview/electron-browser/contextmenuService'; @@ -58,6 +59,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/node/configurationResolverService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { ITitleService } from 'vs/workbench/services/title/common/titleService'; import { WorkbenchMessageService } from 'vs/workbench/services/message/browser/messageService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService } from 'vs/workbench/services/quickopen/common/quickOpenService'; @@ -67,6 +69,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { TextFileService } from 'vs/workbench/services/textfile/electron-browser/textFileService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -76,6 +80,7 @@ import { MenuService } from 'vs/platform/actions/common/menuService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWindowConfiguration } from 'vs/workbench/electron-browser/common'; export const MessagesVisibleContext = new RawContextKey('globalMessageVisible', false); export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); @@ -94,6 +99,7 @@ export interface IWorkbenchCallbacks { const Identifiers = { WORKBENCH_CONTAINER: 'workbench.main.container', + TITLEBAR_PART: 'workbench.parts.titlebar', ACTIVITYBAR_PART: 'workbench.parts.activitybar', SIDEBAR_PART: 'workbench.parts.sidebar', PANEL_PART: 'workbench.parts.panel', @@ -117,6 +123,7 @@ export class Workbench implements IPartService { public _serviceBrand: any; + private parent: HTMLElement; private container: HTMLElement; private workbenchParams: WorkbenchParams; private workbenchContainer: Builder; @@ -128,6 +135,7 @@ export class Workbench implements IPartService { private contextKeyService: IContextKeyService; private keybindingService: IKeybindingService; private configurationEditingService: IConfigurationEditingService; + private titlebarPart: TitlebarPart; private activitybarPart: ActivitybarPart; private sidebarPart: SidebarPart; private panelPart: PanelPart; @@ -151,6 +159,7 @@ export class Workbench implements IPartService { private hasFilesToCreateOpenOrDiff: boolean; constructor( + parent: HTMLElement, container: HTMLElement, workspace: IWorkspace, options: IOptions, @@ -165,6 +174,7 @@ export class Workbench implements IPartService { @ITelemetryService private telemetryService: ITelemetryService, @IEnvironmentService private environmentService: IEnvironmentService ) { + this.parent = parent; this.container = container; this.workbenchParams = { @@ -345,6 +355,12 @@ export class Workbench implements IPartService { // Services we contribute serviceCollection.set(IPartService, this); + // Title bar + this.titlebarPart = this.instantiationService.createInstance(TitlebarPart, Identifiers.TITLEBAR_PART); + this.toDispose.push(this.titlebarPart); + this.toShutdown.push(this.titlebarPart); + serviceCollection.set(ITitleService, this.titlebarPart); + // Status bar this.statusbarPart = this.instantiationService.createInstance(StatusbarPart, Identifiers.STATUSBAR_PART); this.toDispose.push(this.statusbarPart); @@ -400,6 +416,9 @@ export class Workbench implements IPartService { // Text File Service serviceCollection.set(ITextFileService, this.instantiationService.createInstance(TextFileService)); + // Text Model Resolver Service + serviceCollection.set(ITextModelResolverService, this.instantiationService.createInstance(TextModelResolverService)); + // Configuration Editing this.configurationEditingService = this.instantiationService.createInstance(ConfigurationEditingService); serviceCollection.set(IConfigurationEditingService, this.configurationEditingService); @@ -493,6 +512,9 @@ export class Workbench implements IPartService { public getContainer(part: Parts): HTMLElement { let container: Builder = null; switch (part) { + case Parts.TITLEBAR_PART: + container = this.titlebarPart.getContainer(); + break; case Parts.ACTIVITYBAR_PART: container = this.activitybarPart.getContainer(); break; @@ -514,6 +536,8 @@ export class Workbench implements IPartService { public isVisible(part: Parts): boolean { switch (part) { + case Parts.TITLEBAR_PART: + return this.isTitleBarHidden(); case Parts.SIDEBAR_PART: return !this.sideBarHidden; case Parts.PANEL_PART: @@ -527,6 +551,21 @@ export class Workbench implements IPartService { return true; // any other part cannot be hidden } + public isTitleBarHidden(): boolean { + if (!isMacintosh) { + return true; // custom title bar is only supported on Mac currently + } + + const isDev = !this.environmentService.isBuilt || this.environmentService.extensionDevelopmentPath; + if (isDev) { + return true; // not enabled when developing due to https://github.com/electron/electron/issues/3647 + } + + const windowConfig = this.configurationService.getConfiguration(); + + return (windowConfig && windowConfig.window && windowConfig.window.titleBarStyle === 'native'); + } + public isStatusBarHidden(): boolean { return this.statusBarHidden; } @@ -536,7 +575,7 @@ export class Workbench implements IPartService { // Layout if (!skipLayout) { - this.workbenchLayout.layout({ forceStyleReCompute: true }); + this.workbenchLayout.layout({ forceStyleRecompute: true }); } } @@ -556,7 +595,7 @@ export class Workbench implements IPartService { // Layout if (!skipLayout) { - this.workbenchLayout.layout({ forceStyleReCompute: true }); + this.workbenchLayout.layout({ forceStyleRecompute: true }); } } @@ -576,7 +615,7 @@ export class Workbench implements IPartService { // Layout if (!skipLayout) { - this.workbenchLayout.layout({ forceStyleReCompute: true }); + this.workbenchLayout.layout({ forceStyleRecompute: true }); } // If sidebar becomes hidden, also hide the current active Viewlet if any @@ -623,7 +662,7 @@ export class Workbench implements IPartService { // Layout if (!skipLayout) { - this.workbenchLayout.layout({ forceStyleReCompute: true }); + this.workbenchLayout.layout({ forceStyleRecompute: true }); } // If panel part becomes hidden, also hide the current active panel if any @@ -651,7 +690,7 @@ export class Workbench implements IPartService { } public toggleMaximizedPanel(): void { - this.workbenchLayout.layout({ forceStyleReCompute: true, toggleMaximizedPanel: true }); + this.workbenchLayout.layout({ forceStyleRecompute: true, toggleMaximizedPanel: true }); } public getSideBarPosition(): Position { @@ -674,7 +713,7 @@ export class Workbench implements IPartService { this.sidebarPart.getContainer().addClass(newPositionValue); // Layout - this.workbenchLayout.layout({ forceStyleReCompute: true }); + this.workbenchLayout.layout({ forceStyleRecompute: true }); } public dispose(): void { @@ -690,9 +729,9 @@ export class Workbench implements IPartService { * Asks the workbench and all its UI components inside to lay out according to * the containers dimension the workbench is living in. */ - public layout(): void { + public layout(options?: ILayoutOptions): void { if (this.isStarted()) { - this.workbenchLayout.layout(); + this.workbenchLayout.layout(options); } } @@ -753,21 +792,18 @@ export class Workbench implements IPartService { } private createWorkbenchLayout(): void { - const options = new LayoutOptions(); - options.setMargin(new Box(0, 0, 0, 0)); - this.workbenchLayout = this.instantiationService.createInstance(WorkbenchLayout, $(this.container), // Parent this.workbench, // Workbench Container { + titlebar: this.titlebarPart, // Title Bar activitybar: this.activitybarPart, // Activity Bar editor: this.editorPart, // Editor sidebar: this.sidebarPart, // Sidebar panel: this.panelPart, // Panel Part statusbar: this.statusbarPart, // Statusbar }, - this.quickOpen, // Quickopen - options // Layout Options + this.quickOpen // Quickopen ); this.toDispose.push(this.workbenchLayout); @@ -798,7 +834,13 @@ export class Workbench implements IPartService { this.workbench.addClass('no-workspace'); } + // Apply title style if shown + if (!this.isTitleBarHidden()) { + DOM.addClass(this.parent, 'titlebar-style-custom'); + } + // Create Parts + this.createTitlebarPart(); this.createActivityBarPart(); this.createSidebarPart(); this.createEditorPart(); @@ -809,6 +851,16 @@ export class Workbench implements IPartService { this.workbenchContainer.build(this.container); } + private createTitlebarPart(): void { + const titlebarContainer = $(this.workbench).div({ + 'class': ['part', 'titlebar'], + id: Identifiers.TITLEBAR_PART, + role: 'contentinfo' + }); + + this.titlebarPart.create(titlebarContainer); + } + private createActivityBarPart(): void { const activitybarPartContainer = $(this.workbench) .div({ diff --git a/src/vs/workbench/node/extensionPoints.ts b/src/vs/workbench/node/extensionPoints.ts index f318fd69315..d7da8d6309a 100644 --- a/src/vs/workbench/node/extensionPoints.ts +++ b/src/vs/workbench/node/extensionPoints.ts @@ -8,7 +8,7 @@ import * as nls from 'vs/nls'; import * as Platform from 'vs/base/common/platform'; import pfs = require('vs/base/node/pfs'); -import { IExtensionDescription, IMessage, ExtensionProperties } from 'vs/platform/extensions/common/extensions'; +import { IExtensionDescription, IMessage } from 'vs/platform/extensions/common/extensions'; import Severity from 'vs/base/common/severity'; import { TPromise } from 'vs/base/common/winjs.base'; import { groupBy, values } from 'vs/base/common/collections'; @@ -85,17 +85,13 @@ class ExtensionManifestParser extends ExtensionManifestHandler { public parse(): TPromise { return pfs.readFile(this._absoluteManifestPath).then((manifestContents) => { let errors: json.ParseError[] = []; - const parsed = json.parse(manifestContents.toString(), errors); + const extensionDescription = json.parse(manifestContents.toString(), errors); if (errors.length > 0) { errors.forEach((error) => { this._collector.error(this._absoluteFolderPath, nls.localize('jsonParseFail', "Failed to parse {0}: {1}.", this._absoluteManifestPath, json.getParseErrorMessage(error.error))); }); return null; } - const extensionDescription = ExtensionProperties.reduce((previousValue, currentValue) => { - previousValue[currentValue] = parsed[currentValue]; - return previousValue; - }, {}); return extensionDescription; }, (err) => { this._collector.error(this._absoluteFolderPath, nls.localize('fileReadFail', "Cannot read file {0}: {1}.", this._absoluteManifestPath, err.message)); diff --git a/src/vs/workbench/parts/contentprovider/common/contentprovider.contribution.ts b/src/vs/workbench/parts/contentprovider/common/contentprovider.contribution.ts index 97c896111d9..924f3fc6d0c 100644 --- a/src/vs/workbench/parts/contentprovider/common/contentprovider.contribution.ts +++ b/src/vs/workbench/parts/contentprovider/common/contentprovider.contribution.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; import URI from 'vs/base/common/uri'; @@ -14,21 +13,17 @@ import JSONContributionRegistry = require('vs/platform/jsonschemas/common/jsonCo import { Registry } from 'vs/platform/platform'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; let schemaRegistry = Registry.as(JSONContributionRegistry.Extensions.JSONContribution); export class WorkbenchContentProvider implements IWorkbenchContribution { - private modelService: IModelService; - private modeService: IModeService; - constructor( - @IModelService modelService: IModelService, - @IModeService modeService: IModeService + @IModelService private modelService: IModelService, + @ITextModelResolverService private textModelResolverService: ITextModelResolverService, + @IModeService private modeService: IModeService ) { - this.modelService = modelService; - this.modeService = modeService; - this.start(); } @@ -37,7 +32,7 @@ export class WorkbenchContentProvider implements IWorkbenchContribution { } private start(): void { - ResourceEditorInput.registerResourceContentProvider('vscode', { + this.textModelResolverService.registerTextModelContentProvider('vscode', { provideTextContent: (uri: URI): TPromise => { if (uri.scheme !== 'vscode') { return null; @@ -57,4 +52,4 @@ export class WorkbenchContentProvider implements IWorkbenchContribution { } } -(Registry.as(WorkbenchExtensions.Workbench)).registerWorkbenchContribution(WorkbenchContentProvider); \ No newline at end of file +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkbenchContentProvider); \ No newline at end of file diff --git a/src/vs/workbench/parts/debug/browser/debugActionItems.ts b/src/vs/workbench/parts/debug/browser/debugActionItems.ts index 1dacaa28e1a..5e9150db3c2 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionItems.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionItems.ts @@ -8,9 +8,9 @@ import errors = require('vs/base/common/errors'); import { IAction } from 'vs/base/common/actions'; import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IDebugService, State, IGlobalConfig } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugService, IGlobalConfig } from 'vs/workbench/parts/debug/common/debug'; -export class DebugSelectActionItem extends SelectActionItem { +export class SelectConfigurationActionItem extends SelectActionItem { constructor( action: IAction, @@ -25,15 +25,11 @@ export class DebugSelectActionItem extends SelectActionItem { this.toDispose.push(this.debugService.getViewModel().onDidSelectConfigurationName(name => { this.updateOptions(false); })); - this.toDispose.push(this.debugService.onDidChangeState(() => { - this.enabled = this.debugService.state === State.Inactive; - })); } public render(container: HTMLElement): void { super.render(container); this.updateOptions(true); - this.enabled = this.debugService.state === State.Inactive; } private updateOptions(changeDebugConfiguration: boolean): void { @@ -51,3 +47,17 @@ export class DebugSelectActionItem extends SelectActionItem { } } } + +export class FocusProcessActionItem extends SelectActionItem { + constructor( + action: IAction, + @IDebugService private debugService: IDebugService + ) { + super(null, action, [], -1); + + this.debugService.getViewModel().onDidFocusProcess(p => { + const names = this.debugService.getModel().getProcesses().map(p => p.name); + this.setOptions(names, p ? names.indexOf(p.name) : 0); + }); + } +} diff --git a/src/vs/workbench/parts/debug/browser/debugActions.ts b/src/vs/workbench/parts/debug/browser/debugActions.ts index 986c2aad011..2d283606e82 100644 --- a/src/vs/workbench/parts/debug/browser/debugActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugActions.ts @@ -34,7 +34,8 @@ export class AbstractDebugAction extends Action { constructor( id: string, label: string, cssClass: string, @IDebugService protected debugService: IDebugService, - @IKeybindingService protected keybindingService: IKeybindingService + @IKeybindingService protected keybindingService: IKeybindingService, + public weight?: number ) { super(id, label, cssClass, false); this.debugService = debugService; @@ -104,10 +105,6 @@ export class SelectConfigAction extends AbstractDebugAction { this.debugService.getViewModel().setSelectedConfigurationName(configName); return TPromise.as(null); } - - protected isEnabled(state: debug.State): boolean { - return super.isEnabled(state) && state === debug.State.Inactive; - } } export class StartAction extends AbstractDebugAction { @@ -116,14 +113,19 @@ export class StartAction extends AbstractDebugAction { constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService, @ICommandService private commandService: ICommandService) { super(id, label, 'debug-action start', debugService, keybindingService); + this.debugService.getViewModel().onDidSelectConfigurationName(() => { + this.updateEnablement(); + }); } public run(): TPromise { return this.commandService.executeCommand('_workbench.startDebug', this.debugService.getViewModel().selectedConfigurationName); } + // Disabled if the launch drop down shows the launch config that is already running. protected isEnabled(state: debug.State): boolean { - return super.isEnabled(state) && state === debug.State.Inactive; + const process = this.debugService.getModel().getProcesses(); + return super.isEnabled(state) && process.every(p => p.name !== this.debugService.getViewModel().selectedConfigurationName); } } @@ -133,7 +135,7 @@ export class RestartAction extends AbstractDebugAction { static RECONNECT_LABEL = nls.localize('reconnectDebug', "Reconnect"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action restart', debugService, keybindingService); + super(id, label, 'debug-action restart', debugService, keybindingService, 70); this.setLabel(this.debugService.getViewModel().focusedProcess); this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => this.setLabel(this.debugService.getViewModel().focusedProcess))); } @@ -157,7 +159,7 @@ export class StepOverAction extends AbstractDebugAction { static LABEL = nls.localize('stepOverDebug', "Step Over"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action step-over', debugService, keybindingService); + super(id, label, 'debug-action step-over', debugService, keybindingService, 20); } public run(thread: debug.IThread): TPromise { @@ -178,7 +180,7 @@ export class StepIntoAction extends AbstractDebugAction { static LABEL = nls.localize('stepIntoDebug', "Step Into"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action step-into', debugService, keybindingService); + super(id, label, 'debug-action step-into', debugService, keybindingService, 30); } public run(thread: debug.IThread): TPromise { @@ -199,7 +201,7 @@ export class StepOutAction extends AbstractDebugAction { static LABEL = nls.localize('stepOutDebug', "Step Out"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action step-out', debugService, keybindingService); + super(id, label, 'debug-action step-out', debugService, keybindingService, 40); } public run(thread: debug.IThread): TPromise { @@ -220,7 +222,7 @@ export class StepBackAction extends AbstractDebugAction { static LABEL = nls.localize('stepBackDebug', "Step Back"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action step-back', debugService, keybindingService); + super(id, label, 'debug-action step-back', debugService, keybindingService, 50); } public run(thread: debug.IThread): TPromise { @@ -243,7 +245,7 @@ export class StopAction extends AbstractDebugAction { static LABEL = nls.localize('stopDebug', "Stop"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action stop', debugService, keybindingService); + super(id, label, 'debug-action stop', debugService, keybindingService, 80); } public run(): TPromise { @@ -261,7 +263,7 @@ export class DisconnectAction extends AbstractDebugAction { static LABEL = nls.localize('disconnectDebug', "Disconnect"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action disconnect', debugService, keybindingService); + super(id, label, 'debug-action disconnect', debugService, keybindingService, 80); } public run(): TPromise { @@ -279,7 +281,7 @@ export class ContinueAction extends AbstractDebugAction { static LABEL = nls.localize('continueDebug', "Continue"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action continue', debugService, keybindingService); + super(id, label, 'debug-action continue', debugService, keybindingService, 10); } public run(thread: debug.IThread): TPromise { @@ -300,7 +302,7 @@ export class PauseAction extends AbstractDebugAction { static LABEL = nls.localize('pauseDebug', "Pause"); constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { - super(id, label, 'debug-action pause', debugService, keybindingService); + super(id, label, 'debug-action pause', debugService, keybindingService, 10); } public run(thread: debug.IThread): TPromise { @@ -907,3 +909,17 @@ export class RunAction extends AbstractDebugAction { return super.isEnabled(state) && state === debug.State.Inactive; } } + +export class FocusProcessAction extends AbstractDebugAction { + static ID = 'workbench.action.debug.focusProcess'; + static LABEL = nls.localize('focusProcess', "Focus Process"); + + constructor(id: string, label: string, @IDebugService debugService: IDebugService, @IKeybindingService keybindingService: IKeybindingService) { + super(id, label, null, debugService, keybindingService, 100); + } + + public run(processName: string): TPromise { + const process = this.debugService.getModel().getProcesses().filter(p => p.name === processName).pop(); + return this.debugService.setFocusedStackFrameAndEvaluate(null, process); + } +} diff --git a/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts b/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts index 745d52d8160..ad1b4f5f69d 100644 --- a/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts +++ b/src/vs/workbench/parts/debug/browser/debugActionsWidget.ts @@ -3,20 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import lifecycle = require('vs/base/common/lifecycle'); -import errors = require('vs/base/common/errors'); +import * as lifecycle from 'vs/base/common/lifecycle'; +import * as errors from 'vs/base/common/errors'; import * as strings from 'vs/base/common/strings'; import severity from 'vs/base/common/severity'; -import builder = require('vs/base/browser/builder'); -import dom = require('vs/base/browser/dom'); +import * as builder from 'vs/base/browser/builder'; +import * as dom from 'vs/base/browser/dom'; +import * as arrays from 'vs/base/common/arrays'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import actions = require('vs/base/common/actions'); -import events = require('vs/base/common/events'); -import actionbar = require('vs/base/browser/ui/actionbar/actionbar'); +import { IAction } from 'vs/base/common/actions'; +import { EventType } from 'vs/base/common/events'; +import { ActionBar, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { IPartService } from 'vs/workbench/services/part/common/partService'; -import wbext = require('vs/workbench/common/contributions'); -import debug = require('vs/workbench/parts/debug/common/debug'); -import { PauseAction, ContinueAction, StepBackAction, StopAction, DisconnectAction, StepOverAction, StepIntoAction, StepOutAction, RestartAction } from 'vs/workbench/parts/debug/browser/debugActions'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import * as debug from 'vs/workbench/parts/debug/common/debug'; +import { AbstractDebugAction, PauseAction, ContinueAction, StepBackAction, StopAction, DisconnectAction, StepOverAction, StepIntoAction, StepOutAction, RestartAction, FocusProcessAction } from 'vs/workbench/parts/debug/browser/debugActions'; +import { FocusProcessActionItem } from 'vs/workbench/parts/debug/browser/debugActionItems'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IMessageService } from 'vs/platform/message/common/message'; @@ -27,21 +29,19 @@ import IDebugService = debug.IDebugService; const $ = builder.$; const DEBUG_ACTIONS_WIDGET_POSITION_KEY = 'debug.actionswidgetposition'; -export class DebugActionsWidget implements wbext.IWorkbenchContribution { +export class DebugActionsWidget implements IWorkbenchContribution { private static ID = 'debug.actionsWidget'; private $el: builder.Builder; private dragArea: builder.Builder; private toDispose: lifecycle.IDisposable[]; - private actionBar: actionbar.ActionBar; - private actions: actions.IAction[]; - private pauseAction: PauseAction; - private continueAction: ContinueAction; - private stepBackAction: StepBackAction; - private stopAction: StopAction; - private disconnectAction: DisconnectAction; + private actionBar: ActionBar; + private allActions: AbstractDebugAction[]; + private activeActions: AbstractDebugAction[]; + private isVisible: boolean; private isBuilt: boolean; + private focusProcessActionItem: FocusProcessActionItem; constructor( @IMessageService private messageService: IMessageService, @@ -59,8 +59,21 @@ export class DebugActionsWidget implements wbext.IWorkbenchContribution { this.$el.append(actionBarContainter); this.toDispose = []; - this.actionBar = new actionbar.ActionBar(actionBarContainter, { - orientation: actionbar.ActionsOrientation.HORIZONTAL + this.activeActions = []; + this.actionBar = new ActionBar(actionBarContainter, { + orientation: ActionsOrientation.HORIZONTAL, + actionItemProvider: (action: IAction) => { + if (action.id === FocusProcessAction.ID) { + if (!this.focusProcessActionItem) { + this.focusProcessActionItem = this.instantiationService.createInstance(FocusProcessActionItem, action); + this.toDispose.push(this.focusProcessActionItem); + } + + return this.focusProcessActionItem; + } + + return null; + } }); this.toDispose.push(this.actionBar); @@ -74,7 +87,7 @@ export class DebugActionsWidget implements wbext.IWorkbenchContribution { this.toDispose.push(this.debugService.onDidChangeState(() => { this.update(); })); - this.toDispose.push(this.actionBar.actionRunner.addListener2(events.EventType.RUN, (e: any) => { + this.toDispose.push(this.actionBar.actionRunner.addListener2(EventType.RUN, (e: any) => { // check for error if (e.error && !errors.isPromiseCanceledError(e.error)) { this.messageService.show(severity.Error, e.error); @@ -138,8 +151,12 @@ export class DebugActionsWidget implements wbext.IWorkbenchContribution { return this.hide(); } - this.actionBar.clear(); - this.actionBar.push(this.getActions(this.instantiationService, this.debugService.state), { icon: true, label: false }); + const actions = this.getActions(); + if (!arrays.equals(actions, this.activeActions, (first, second) => first.id === second.id)) { + this.actionBar.clear(); + this.actionBar.push(actions, { icon: true, label: false }); + this.activeActions = actions; + } this.show(); } @@ -162,43 +179,50 @@ export class DebugActionsWidget implements wbext.IWorkbenchContribution { this.$el.hide(); } - private getActions(instantiationService: IInstantiationService, state: debug.State): actions.IAction[] { - if (!this.actions) { - this.continueAction = instantiationService.createInstance(ContinueAction, ContinueAction.ID, ContinueAction.LABEL); - this.pauseAction = instantiationService.createInstance(PauseAction, PauseAction.ID, PauseAction.LABEL); - this.stopAction = instantiationService.createInstance(StopAction, StopAction.ID, StopAction.LABEL); - this.disconnectAction = instantiationService.createInstance(DisconnectAction, DisconnectAction.ID, DisconnectAction.LABEL); - this.actions = [ - this.continueAction, - instantiationService.createInstance(StepOverAction, StepOverAction.ID, StepOverAction.LABEL), - instantiationService.createInstance(StepIntoAction, StepIntoAction.ID, StepIntoAction.LABEL), - instantiationService.createInstance(StepOutAction, StepOutAction.ID, StepOutAction.LABEL), - instantiationService.createInstance(RestartAction, RestartAction.ID, RestartAction.LABEL), - this.stopAction - ]; - - this.actions.forEach(a => { + private getActions(): AbstractDebugAction[] { + if (!this.allActions) { + this.allActions = []; + this.allActions.push(this.instantiationService.createInstance(ContinueAction, ContinueAction.ID, ContinueAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(PauseAction, PauseAction.ID, PauseAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(StopAction, StopAction.ID, StopAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(DisconnectAction, DisconnectAction.ID, DisconnectAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(StepOverAction, StepOverAction.ID, StepOverAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(StepIntoAction, StepIntoAction.ID, StepIntoAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(StepOutAction, StepOutAction.ID, StepOutAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(RestartAction, RestartAction.ID, RestartAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(StepBackAction, StepBackAction.ID, StepBackAction.LABEL)); + this.allActions.push(this.instantiationService.createInstance(FocusProcessAction, FocusProcessAction.ID, FocusProcessAction.LABEL)); + this.allActions.forEach(a => { this.toDispose.push(a); }); - this.toDispose.push(this.pauseAction); - this.toDispose.push(this.disconnectAction); } - this.actions[0] = state === debug.State.Running ? this.pauseAction : this.continueAction; + const state = this.debugService.state; const process = this.debugService.getViewModel().focusedProcess; - this.actions[5] = (process && !strings.equalsIgnoreCase(process.session.configuration.type, 'extensionHost') && process.session.requestType === debug.SessionRequestType.ATTACH) ? this.disconnectAction : this.stopAction; + const attached = process && !strings.equalsIgnoreCase(process.session.configuration.type, 'extensionHost') && process.session.requestType === debug.SessionRequestType.ATTACH; - if (process && process.session.configuration.capabilities.supportsStepBack) { - if (!this.stepBackAction) { - this.stepBackAction = instantiationService.createInstance(StepBackAction, StepBackAction.ID, StepBackAction.LABEL); - this.toDispose.push(this.stepBackAction); + return this.allActions.filter(a => { + if (a.id === ContinueAction.ID) { + return state !== debug.State.Running; + } + if (a.id === PauseAction.ID) { + return state === debug.State.Running; + } + if (a.id === StepBackAction.ID) { + return process && process.session.configuration.capabilities.supportsStepBack; + } + if (a.id === DisconnectAction.ID) { + return attached; + } + if (a.id === StopAction.ID) { + return !attached; + } + if (a.id === FocusProcessAction.ID) { + return this.debugService.getViewModel().isMultiProcessView(); } - // Return a copy of this.actions containing stepBackAction - return [...this.actions.slice(0, 4), this.stepBackAction, ...this.actions.slice(4)]; - } else { - return this.actions; - } + return true; + }).sort((first, second) => first.weight - second.weight); } public dispose(): void { diff --git a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts index b8e621b6569..654c37f5100 100644 --- a/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts +++ b/src/vs/workbench/parts/debug/browser/debugEditorModelManager.ts @@ -295,7 +295,12 @@ export class DebugEditorModelManager implements IWorkbenchContribution { const mode = modelData ? modelData.model.getMode() : null; const modeId = mode ? mode.getId() : ''; - const condition = breakpoint.condition ? breakpoint.condition : breakpoint.hitCondition; + let condition: string; + if (breakpoint.condition && breakpoint.hitCondition) { + condition = `Expression: ${breakpoint.condition}\nHitCount: ${breakpoint.hitCondition}`; + } else { + condition = breakpoint.condition ? breakpoint.condition : breakpoint.hitCondition; + } const glyphMarginHoverMessage = `\`\`\`${modeId}\n${condition}\`\`\``; return { diff --git a/src/vs/workbench/parts/debug/browser/debugViewlet.ts b/src/vs/workbench/parts/debug/browser/debugViewlet.ts index b73d291b8e9..0be7eaa420b 100644 --- a/src/vs/workbench/parts/debug/browser/debugViewlet.ts +++ b/src/vs/workbench/parts/debug/browser/debugViewlet.ts @@ -140,7 +140,7 @@ export class DebugViewlet extends Viewlet { public getActionItem(action: actions.IAction): actionbar.IActionItem { if (action.id === debugactions.SelectConfigAction.ID) { - return this.instantiationService.createInstance(dbgactionitems.DebugSelectActionItem, action); + return this.instantiationService.createInstance(dbgactionitems.SelectConfigurationActionItem, action); } return null; diff --git a/src/vs/workbench/parts/debug/browser/media/debug.contribution.css b/src/vs/workbench/parts/debug/browser/media/debug.contribution.css index f400006f221..92cfd72cd98 100644 --- a/src/vs/workbench/parts/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/parts/debug/browser/media/debug.contribution.css @@ -131,15 +131,32 @@ background-color: #F3F3F3; box-shadow: 0 2px 8px #A8A8A8; position: absolute; + top: 0; z-index: 200; height: 32px; - padding-top: 3px; left: 50%; margin-left: -96px; display: flex; padding-left: 7px; } +.titlebar-style-custom .monaco-workbench.fullscreen .debug-actions-widget { + top: 0; +} + +.titlebar-style-custom .monaco-workbench .debug-actions-widget { + top: 22px; /* push down debug toolbar when we have a custom title bar */ +} + +.monaco-workbench .debug-actions-widget .monaco-action-bar .action-item.select-container { + margin-right: 7px; +} + +.monaco-workbench .debug-actions-widget .monaco-action-bar .action-item .select-box { + background-color: initial; + margin-top: 6px; +} + .monaco-workbench .debug-actions-widget .drag-area { cursor: -webkit-grab; height: 32px; diff --git a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css index d5ad9caa8f6..09c6180a57e 100644 --- a/src/vs/workbench/parts/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/parts/debug/browser/media/debugViewlet.css @@ -60,7 +60,8 @@ } .debug-viewlet .monaco-tree .monaco-tree-row.selected .line-number, -.debug-viewlet .monaco-tree .monaco-tree-row.selected .thread > .state > .label { +.debug-viewlet .monaco-tree .monaco-tree-row.selected .thread > .state > .label, +.debug-viewlet .monaco-tree .monaco-tree-row.selected .process > .state > .label { background-color: #ffffff; color: #666; } @@ -123,11 +124,13 @@ color: inherit; } -.debug-viewlet .debug-call-stack .thread { +.debug-viewlet .debug-call-stack .thread, +.debug-viewlet .debug-call-stack .process { display: flex; } -.debug-viewlet .debug-call-stack .thread > .state { +.debug-viewlet .debug-call-stack .thread > .state, +.debug-viewlet .debug-call-stack .process > .state { flex: 1; text-align: right; overflow: hidden; @@ -136,7 +139,8 @@ text-transform: uppercase; } -.debug-viewlet .debug-call-stack .thread > .state > .label { +.debug-viewlet .debug-call-stack .thread > .state > .label, +.debug-viewlet .debug-call-stack .process > .state > .label { background: rgba(136, 136, 136, 0.3); border-radius: 2px; font-size: 0.8em; diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 8c5a8a19e47..2f566cf5a39 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -235,7 +235,10 @@ export interface IViewModel extends ITreeElement { selectedConfigurationName: string; setSelectedConfigurationName(name: string): void; + isMultiProcessView(): boolean; + onDidFocusStackFrame: Event; + onDidFocusProcess: Event; onDidSelectExpression: Event; onDidSelectFunctionBreakpoint: Event; /** @@ -371,7 +374,7 @@ export interface IDebugService { /** * Sets the focused stack frame and evaluates all expresions against the newly focused stack frame, */ - setFocusedStackFrameAndEvaluate(focusedStackFrame: IStackFrame): TPromise; + setFocusedStackFrameAndEvaluate(focusedStackFrame: IStackFrame, process?: IProcess): TPromise; /** * Adds new breakpoints to the model for the file specified with the uri. Notifies debug adapter of breakpoint changes. diff --git a/src/vs/workbench/parts/debug/common/debugProtocol.d.ts b/src/vs/workbench/parts/debug/common/debugProtocol.d.ts index 585f70172b8..3ff4c1d795f 100644 --- a/src/vs/workbench/parts/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/parts/debug/common/debugProtocol.d.ts @@ -654,7 +654,7 @@ declare module DebugProtocol { /** Response to 'setVariable' request. */ export interface SetVariableResponse extends Response { body: { - /** The new value of the variable. */ + /** The new value of the variable. See capability 'supportsValueEscaping' for details about how to treat newlines in multi-line strings. */ value: string; /** The type of the new value. Typically shown in the UI when hovering over the value. */ type?: string; @@ -756,7 +756,7 @@ declare module DebugProtocol { /** Response to 'evaluate' request. */ export interface EvaluateResponse extends Response { body: { - /** The result of the evaluate request. */ + /** The result of the evaluate request. See capability 'supportsValueEscaping' for details about how to treat newlines in multi-lines strings. */ result: string; /** The optional type of the evaluate result. */ type?: string; @@ -886,6 +886,8 @@ declare module DebugProtocol { additionalModuleColumns?: ColumnDescriptor[]; /** Checksum algorithms supported by the debug adapter. */ supportedChecksumAlgorithms?: ChecksumAlgorithm[]; + /** The debug adapter will be responsible for escaping newlines in variable values and evaluation results, and the client will display them as-is. If missing or false the client will escape newlines as needed. */ + supportsValueEscaping?: boolean; } /** An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with. */ @@ -1059,7 +1061,7 @@ declare module DebugProtocol { export interface Variable { /** The variable's name. */ name: string; - /** The variable's value. For structured objects this can be a multi line text, e.g. for a function the body of a function. */ + /** The variable's value. This can be a multi-line text, e.g. for a function the body of a function. See capability 'supportsValueEscaping' for details about how to treat newlines in multi-line strings. */ value: string; /** The type of the variable's value. Typically shown in the UI when hovering over the value. */ type?: string; diff --git a/src/vs/workbench/parts/debug/common/debugViewModel.ts b/src/vs/workbench/parts/debug/common/debugViewModel.ts index 90b2e851091..6a97968a42e 100644 --- a/src/vs/workbench/parts/debug/common/debugViewModel.ts +++ b/src/vs/workbench/parts/debug/common/debugViewModel.ts @@ -13,13 +13,16 @@ export class ViewModel implements debug.IViewModel { private selectedExpression: debug.IExpression; private selectedFunctionBreakpoint: debug.IFunctionBreakpoint; private _onDidFocusStackFrame: Emitter; + private _onDidFocusProcess: Emitter; private _onDidSelectExpression: Emitter; private _onDidSelectFunctionBreakpoint: Emitter; private _onDidSelectConfigurationName: Emitter; + private multiProcessView: boolean; public changedWorkbenchViewState: boolean; constructor(private _selectedConfigurationName: string) { this._onDidFocusStackFrame = new Emitter(); + this._onDidFocusProcess = new Emitter(); this._onDidSelectExpression = new Emitter(); this._onDidSelectFunctionBreakpoint = new Emitter(); this._onDidSelectConfigurationName = new Emitter(); @@ -46,12 +49,17 @@ export class ViewModel implements debug.IViewModel { this._focusedStackFrame = stackFrame; this._focusedProcess = process; this._onDidFocusStackFrame.fire(stackFrame); + this._onDidFocusProcess.fire(process); } public get onDidFocusStackFrame(): Event { return this._onDidFocusStackFrame.event; } + public get onDidFocusProcess(): Event { + return this._onDidFocusProcess.event; + } + public getSelectedExpression(): debug.IExpression { return this.selectedExpression; } @@ -87,6 +95,14 @@ export class ViewModel implements debug.IViewModel { this._onDidSelectConfigurationName.fire(configurationName); } + public isMultiProcessView(): boolean { + return this.multiProcessView; + } + + public setMultiProcessView(isMultiProcessView: boolean): void { + this.multiProcessView = isMultiProcessView; + } + public get onDidSelectConfigurationName(): Event { return this._onDidSelectConfigurationName.event; } diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index be06e7a9d4d..b0301cf4fdf 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -28,6 +28,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IFileService, FileChangesEvent, FileChangeType, EventType } from 'vs/platform/files/common/files'; import { IEventService } from 'vs/platform/event/common/event'; import { IMessageService, CloseAction } from 'vs/platform/message/common/message'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc'; @@ -54,7 +55,6 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWindowIPCService, IBroadcast } from 'vs/workbench/services/window/electron-browser/windowService'; import { ILogEntry, EXTENSION_LOG_BROADCAST_CHANNEL, EXTENSION_ATTACH_BROADCAST_CHANNEL, EXTENSION_TERMINATE_BROADCAST_CHANNEL } from 'vs/workbench/electron-browser/extensionHost'; -import { ipcRenderer as ipc } from 'electron'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; @@ -87,6 +87,7 @@ export class DebugService implements debug.IDebugService { @IFileService private fileService: IFileService, @IMessageService private messageService: IMessageService, @IPartService private partService: IPartService, + @IWindowsService private windowsService: IWindowsService, @IWindowIPCService private windowService: IWindowIPCService, @ITelemetryService private telemetryService: ITelemetryService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @@ -352,7 +353,7 @@ export class DebugService implements debug.IDebugService { this.toDisposeOnSessionEnd[session.getId()].push(session.onDidExitAdapter(event => { // 'Run without debugging' mode VSCode must terminate the extension host. More details: #3905 if (session && session.configuration.type === 'extensionHost' && this.sessionStates[session.getId()] === debug.State.RunningNoDebug) { - ipc.send('vscode:closeExtensionHostWindow', this.contextService.getWorkspace().resource.fsPath); + this.windowsService.closeExtensionHostWindow(this.contextService.getWorkspace().resource.fsPath); } if (session && session.getId() === event.body.sessionId) { this.onSessionEnd(session); @@ -640,6 +641,9 @@ export class DebugService implements debug.IDebugService { const session = this.instantiationService.createInstance(RawDebugSession, sessionId, configuration.debugServer, adapter, this.customTelemetryService); const process = this.model.addProcess(configuration.name, session); + if (this.model.getProcesses().length > 1) { + this.viewModel.setMultiProcessView(true); + } if (!this.viewModel.focusedProcess) { this.viewModel.setFocusedStackFrame(null, process); this._onDidChangeState.fire(); @@ -817,6 +821,7 @@ export class DebugService implements debug.IDebugService { this.model.updateBreakpoints(data); this.inDebugMode.reset(); + this.viewModel.setMultiProcessView(false); if (!this.partService.isSideBarHidden() && this.configurationService.getConfiguration('debug').openExplorerOnEnd) { this.viewletService.openViewlet(EXPLORER_VIEWLET_ID).done(null, errors.onUnexpectedError); diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts index f179a4825f1..50999287b74 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViewer.ts @@ -226,9 +226,7 @@ export class CallStackController extends BaseDebugController { if (element instanceof ThreadAndProcessIds) { return this.showMoreStackFrames(tree, element); } - if (element instanceof StackFrame) { - this.focusStackFrame(element, event, true); - } + this.focusStackFrame(element, event, true); return super.onLeftClick(tree, element, event); } @@ -238,9 +236,7 @@ export class CallStackController extends BaseDebugController { if (element instanceof ThreadAndProcessIds) { return this.showMoreStackFrames(tree, element); } - if (element instanceof StackFrame) { - this.focusStackFrame(element, event, false); - } + this.focusStackFrame(element, event, false); return super.onEnter(tree, event); } @@ -285,8 +281,21 @@ export class CallStackController extends BaseDebugController { return true; } - private focusStackFrame(stackFrame: debug.IStackFrame, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { - this.debugService.setFocusedStackFrameAndEvaluate(stackFrame).done(null, errors.onUnexpectedError); + private focusStackFrame(element: any, event: IKeyboardEvent | IMouseEvent, preserveFocus: boolean): void { + let stackFrame: debug.IStackFrame; + let process: debug.IProcess; + if (element instanceof StackFrame) { + stackFrame = element; + process = element.thread.process; + } + if (element instanceof Thread) { + process = element.process; + } + if (element instanceof Process) { + process = element; + } + + this.debugService.setFocusedStackFrameAndEvaluate(stackFrame, process).done(null, errors.onUnexpectedError); if (stackFrame) { const sideBySide = (event && (event.ctrlKey || event.metaKey)); @@ -395,6 +404,8 @@ interface IThreadTemplateData { interface IProcessTemplateData { process: HTMLElement; name: HTMLElement; + state: HTMLElement; + stateLabel: HTMLSpanElement; } interface IErrorTemplateData { @@ -451,6 +462,8 @@ export class CallStackRenderer implements IRenderer { let data: IProcessTemplateData = Object.create(null); data.process = dom.append(container, $('.process')); data.name = dom.append(data.process, $('.name')); + data.state = dom.append(data.process, $('.state')); + data.stateLabel = dom.append(data.state, $('span.label')); return data; } @@ -504,13 +517,18 @@ export class CallStackRenderer implements IRenderer { private renderProcess(process: debug.IProcess, data: IProcessTemplateData): void { data.process.title = nls.localize({ key: 'process', comment: ['Process is a noun'] }, "Process"); data.name.textContent = process.name; + const stoppedThread = process.getAllThreads().filter(t => t.stopped).pop(); + + data.stateLabel.textContent = stoppedThread ? nls.localize('paused', "Paused") + : nls.localize({ key: 'running', comment: ['indicates state'] }, "Running"); } private renderThread(thread: debug.IThread, data: IThreadTemplateData): void { data.thread.title = nls.localize('thread', "Thread"); data.name.textContent = thread.name; - data.stateLabel.textContent = thread.stopped ? nls.localize('paused', "paused") - : nls.localize({ key: 'running', comment: ['indicates state'] }, "running"); + + data.stateLabel.textContent = thread.stopped ? nls.localize('pausedOn', "Paused on {0}", thread.stoppedDetails.reason) + : nls.localize({ key: 'running', comment: ['indicates state'] }, "Running"); } private renderError(element: string, data: IErrorTemplateData) { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugViews.ts b/src/vs/workbench/parts/debug/electron-browser/debugViews.ts index 5cd54d20588..4c978c7dcb5 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugViews.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugViews.ts @@ -13,12 +13,12 @@ import * as errors from 'vs/base/common/errors'; import { EventType } from 'vs/base/common/events'; import { IActionRunner, IAction } from 'vs/base/common/actions'; import { prepareActions } from 'vs/workbench/browser/actionBarRegistry'; -import { ITreeOptions, IFocusEvent, IHighlightEvent, ITree } from 'vs/base/parts/tree/browser/tree'; +import { ITreeOptions, IHighlightEvent, ITree } from 'vs/base/parts/tree/browser/tree'; import { Tree } from 'vs/base/parts/tree/browser/treeImpl'; import { CollapsibleState } from 'vs/base/browser/ui/splitview/splitview'; import { CollapsibleViewletView, AdaptiveCollapsibleViewletView, CollapseAction } from 'vs/workbench/browser/viewlet'; import * as debug from 'vs/workbench/parts/debug/common/debug'; -import { StackFrame, Expression, Variable, ExceptionBreakpoint, FunctionBreakpoint } from 'vs/workbench/parts/debug/common/debugModel'; +import { Expression, Variable, ExceptionBreakpoint, FunctionBreakpoint, Thread } from 'vs/workbench/parts/debug/common/debugModel'; import * as viewer from 'vs/workbench/parts/debug/electron-browser/debugViewer'; import { AddWatchExpressionAction, RemoveAllWatchExpressionsAction, AddFunctionBreakpointAction, ToggleBreakpointsActivatedAction, RemoveAllBreakpointsAction } from 'vs/workbench/parts/debug/browser/debugActions'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; @@ -118,15 +118,6 @@ export class VariablesView extends CollapsibleViewletView { collapseAction.enabled = state === debug.State.Running || state === debug.State.Stopped; })); - this.toDispose.push(this.tree.addListener2(EventType.FOCUS, (e: IFocusEvent) => { - const isMouseClick = (e.payload && e.payload.origin === 'mouse'); - const isVariableType = (e.focus instanceof Variable); - - if (isMouseClick && isVariableType) { - this.telemetryService.publicLog('debug/variables/selected'); - } - })); - this.toDispose.push(this.debugService.getViewModel().onDidSelectExpression(expression => { if (!expression || !(expression instanceof Variable)) { return; @@ -242,7 +233,6 @@ export class CallStackView extends CollapsibleViewletView { private pauseMessage: builder.Builder; private pauseMessageLabel: builder.Builder; private onCallStackChangeScheduler: RunOnceScheduler; - private onStackFrameFocusScheduler: RunOnceScheduler; constructor( actionRunner: IActionRunner, @@ -256,47 +246,41 @@ export class CallStackView extends CollapsibleViewletView { ) { super(actionRunner, !!settings[CallStackView.MEMENTO], nls.localize('callstackSection', "Call Stack Section"), messageService, keybindingService, contextMenuService); - // Create schedulers to prevent unnecessary flashing of tree when reacting to changes - this.onStackFrameFocusScheduler = new RunOnceScheduler(() => { - const stackFrame = this.debugService.getViewModel().focusedStackFrame; - if (!stackFrame) { - this.pauseMessage.hide(); - return; - } - - const thread = stackFrame.thread; - this.tree.expandAll([thread.process, thread]).done(() => { - const focusedStackFrame = this.debugService.getViewModel().focusedStackFrame; - this.tree.setSelection([focusedStackFrame]); - if (thread.stoppedDetails && thread.stoppedDetails.reason) { - this.pauseMessageLabel.text(nls.localize('debugStopped', "Paused on {0}", thread.stoppedDetails.reason)); - if (thread.stoppedDetails.text) { - this.pauseMessageLabel.title(thread.stoppedDetails.text); - } - thread.stoppedDetails.reason === 'exception' ? this.pauseMessageLabel.addClass('exception') : this.pauseMessageLabel.removeClass('exception'); - this.pauseMessage.show(); - } else { - this.pauseMessage.hide(); - } - - return this.tree.reveal(focusedStackFrame); - }, errors.onUnexpectedError); - }, 100); - + // Create scheduler to prevent unnecessary flashing of tree when reacting to changes this.onCallStackChangeScheduler = new RunOnceScheduler(() => { let newTreeInput: any = this.debugService.getModel(); const processes = this.debugService.getModel().getProcesses(); - if (processes.length === 1) { + if (!this.debugService.getViewModel().isMultiProcessView() && processes.length) { const threads = processes[0].getAllThreads(); // Only show the threads in the call stack if there is more than 1 thread. newTreeInput = threads.length === 1 ? threads[0] : processes[0]; } - if (this.tree.getInput() === newTreeInput) { - this.tree.refresh().done(null, errors.onUnexpectedError); + // Only show the global pause message if we do not display threads. + // Otherwsie there will be a pause message per thread and there is no need for a global one. + if (newTreeInput instanceof Thread && newTreeInput.stoppedDetails) { + this.pauseMessageLabel.text(nls.localize('debugStopped', "Paused on {0}", newTreeInput.stoppedDetails.reason)); + if (newTreeInput.stoppedDetails.text) { + this.pauseMessageLabel.title(newTreeInput.stoppedDetails.text); + } + newTreeInput.stoppedDetails.reason === 'exception' ? this.pauseMessageLabel.addClass('exception') : this.pauseMessageLabel.removeClass('exception'); + this.pauseMessage.show(); } else { - this.tree.setInput(newTreeInput).done(null, errors.onUnexpectedError); + this.pauseMessage.hide(); } + + (this.tree.getInput() === newTreeInput ? this.tree.refresh() : this.tree.setInput(newTreeInput)).done(() => { + const stackFrame = this.debugService.getViewModel().focusedStackFrame; + if (!stackFrame) { + return; + } + + const thread = stackFrame.thread; + return this.tree.expandAll([thread.process, thread]).done(() => { + this.tree.setSelection([stackFrame]); + return this.tree.reveal(stackFrame); + }); + }, errors.onUnexpectedError); }, 50); } @@ -322,21 +306,6 @@ export class CallStackView extends CollapsibleViewletView { controller: new viewer.CallStackController(this.debugService, this.contextMenuService, actionProvider) }, debugTreeOptions(nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'callStackAriaLabel' }, "Debug Call Stack"))); - this.toDispose.push(this.tree.addListener2(EventType.FOCUS, (e: IFocusEvent) => { - const isMouseClick = (e.payload && e.payload.origin === 'mouse'); - const isStackFrameType = (e.focus instanceof StackFrame); - - if (isMouseClick && isStackFrameType) { - this.telemetryService.publicLog('debug/callStack/selected'); - } - })); - - this.toDispose.push(this.debugService.getViewModel().onDidFocusStackFrame(() => { - if (!this.onStackFrameFocusScheduler.isScheduled()) { - this.onStackFrameFocusScheduler.schedule(); - } - })); - this.toDispose.push(this.debugService.getModel().onDidChangeCallStack(() => { if (!this.onCallStackChangeScheduler.isScheduled()) { this.onCallStackChangeScheduler.schedule(); diff --git a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts index 020f469a65c..e5698ef2249 100644 --- a/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/parts/debug/electron-browser/rawDebugSession.ts @@ -307,7 +307,7 @@ export class RawDebugSession extends v8.V8Protocol implements debug.ISession { // Cancel all sent promises on disconnect so debug trees are not left in a broken state #3666. // Give a 1s timeout to give a chance for some promises to complete. setTimeout(() => { - this.sentPromises.forEach(p => p.cancel()); + this.sentPromises.forEach(p => p && p.cancel()); this.sentPromises = []; }, 1000); diff --git a/src/vs/workbench/parts/debug/node/debugAdapter.ts b/src/vs/workbench/parts/debug/node/debugAdapter.ts index a43bc0507cd..1141b1f5ed8 100644 --- a/src/vs/workbench/parts/debug/node/debugAdapter.ts +++ b/src/vs/workbench/parts/debug/node/debugAdapter.ts @@ -149,7 +149,7 @@ export class Adapter { properties.configurationNames = { type: 'array', default: [], - description: nls.localize('debugConfigurationNames', "Configurations that will be launched as part of this \"composite\" configuration. Only respected if type of this configuration is \"composite\".") + description: nls.localize({ key: 'debugConfigurationNames', comment: ['"composite" is not localizable'] }, "Configurations that will be launched as part of this \"composite\" configuration. Only respected if type of this configuration is \"composite\".") }; properties.preLaunchTask = { type: ['string', 'null'], diff --git a/src/vs/workbench/parts/extensions/browser/dependenciesViewer.ts b/src/vs/workbench/parts/extensions/browser/dependenciesViewer.ts index e6f7aef8bf8..d0cbd34242c 100644 --- a/src/vs/workbench/parts/extensions/browser/dependenciesViewer.ts +++ b/src/vs/workbench/parts/extensions/browser/dependenciesViewer.ts @@ -42,7 +42,7 @@ export class DataSource implements IDataSource { } public hasChildren(tree: ITree, element: IExtensionDependencies): boolean { - return element.hasDependencies && !this.isSelfAncestor(element); + return element.hasDependencies; } public getChildren(tree: ITree, element: IExtensionDependencies): Promise { @@ -52,17 +52,6 @@ export class DataSource implements IDataSource { public getParent(tree: ITree, element: IExtensionDependencies): Promise { return TPromise.as(element.dependent); } - - private isSelfAncestor(element: IExtensionDependencies): boolean { - let ancestor = element.dependent; - while (ancestor !== null) { - if (ancestor.identifier === element.identifier) { - return true; - } - ancestor = ancestor.dependent; - } - return false; - } } export class Renderer implements IRenderer { diff --git a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts index 506f02d3007..1d04decb65a 100644 --- a/src/vs/workbench/parts/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/browser/extensionsActions.ts @@ -668,8 +668,6 @@ export class DisableActionItem extends DropDownMenuActionItem { } } - - export class UpdateAllAction extends Action { static ID = 'workbench.extensions.action.updateAllExtensions'; @@ -716,7 +714,7 @@ export class ReloadAction extends Action { get extension(): IExtension { return this._extension; } set extension(extension: IExtension) { this._extension = extension; this.update(); } - private reloadMessaage: string = ''; + reloadMessaage: string = ''; private throttler: Throttler; constructor( diff --git a/src/vs/workbench/parts/extensions/common/extensions.ts b/src/vs/workbench/parts/extensions/common/extensions.ts index d756390fcfc..756bf88db54 100644 --- a/src/vs/workbench/parts/extensions/common/extensions.ts +++ b/src/vs/workbench/parts/extensions/common/extensions.ts @@ -47,7 +47,6 @@ export interface IExtension { telemetryData: any; getManifest(): TPromise; getReadme(): TPromise; - hasChangelog: boolean; getChangelog(): TPromise; } diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts index d763f2c2a37..9ec4af10195 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensionsActions.ts @@ -14,7 +14,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IMessageService } from 'vs/platform/message/common/message'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { remote } from 'electron'; -import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; const dialog = remote.dialog; @@ -26,17 +26,15 @@ export class OpenExtensionsFolderAction extends Action { constructor( id: string, label: string, - @IWindowIPCService private windowService: IWindowIPCService, + @IWindowsService private windowsService: IWindowsService, @IEnvironmentService private environmentService: IEnvironmentService ) { super(id, label, null, true); } - run(): TPromise { + run(): TPromise { const extensionsHome = this.environmentService.extensionsPath; - this.windowService.getWindow().showItemInFolder(paths.normalize(extensionsHome, true)); - - return TPromise.as(true); + return this.windowsService.showItemInFolder(paths.normalize(extensionsHome, true)); } protected isEnabled(): boolean { diff --git a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts index 29739425a0f..e47c20280a5 100644 --- a/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/parts/extensions/node/extensionsWorkbenchService.ts @@ -162,7 +162,7 @@ class Extension implements IExtension { } get outdated(): boolean { - return this.gallery && this.type === LocalExtensionType.User && semver.gt(this.latestVersion, this.version); + return !!this.gallery && this.type === LocalExtensionType.User && semver.gt(this.latestVersion, this.version); } get telemetryData(): any { @@ -201,10 +201,6 @@ class Extension implements IExtension { return this.galleryService.getAsset(readmeUrl).then(asText); } - get hasChangelog(): boolean { - return !!(this.changelogUrl); - } - getChangelog(): TPromise { const changelogUrl = this.changelogUrl; @@ -223,22 +219,27 @@ class Extension implements IExtension { get dependencies(): string[] { const { local, gallery } = this; - if (gallery) { - return gallery.properties.dependencies; - } if (local && local.manifest.extensionDependencies) { return local.manifest.extensionDependencies; } + if (gallery) { + return gallery.properties.dependencies; + } return []; } } class ExtensionDependencies implements IExtensionDependencies { + private _hasDependencies: boolean = null; + constructor(private _extension: IExtension, private _identifier: string, private _map: Map, private _dependent: IExtensionDependencies = null) { } get hasDependencies(): boolean { - return this._extension ? this._extension.dependencies.length > 0 : false; + if (this._hasDependencies === null) { + this._hasDependencies = this.computeHasDependencies(); + } + return this._hasDependencies; } get extension(): IExtension { @@ -254,8 +255,25 @@ class ExtensionDependencies implements IExtensionDependencies { } get dependencies(): IExtensionDependencies[] { + if (!this.hasDependencies) { + return []; + } return this._extension.dependencies.map(d => new ExtensionDependencies(this._map.get(d), d, this._map, this)); } + + private computeHasDependencies(): boolean { + if (this._extension && this._extension.dependencies.length > 0) { + let dependent = this._dependent; + while (dependent !== null) { + if (dependent.identifier === this.identifier) { + return false; + } + dependent = dependent.dependent; + } + return true; + } + return false; + } } function stripVersion(id: string): string { @@ -486,7 +504,6 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { return this.doSetEnablement(extension, enable, workspace).then(reload => { this.telemetryService.publicLog(enable ? 'extension:enable' : 'extension:disable', extension.telemetryData); - this._onChange.fire(); }); } @@ -503,6 +520,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } return this.extensionService.uninstall(local); + } private doSetEnablement(extension: IExtension, enable: boolean, workspace: boolean): TPromise { @@ -511,11 +529,11 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { } const globalElablement = this.extensionEnablementService.setEnablement(extension.identifier, enable, false); - if (!this.workspaceContextService.getWorkspace()) { - return globalElablement; + if (enable && this.workspaceContextService.getWorkspace()) { + const workspaceEnablement = this.extensionEnablementService.setEnablement(extension.identifier, enable, true); + return TPromise.join([globalElablement, workspaceEnablement]).then(values => values[0] || values[1]); } - return TPromise.join([globalElablement, this.extensionEnablementService.setEnablement(extension.identifier, enable, true)]) - .then(values => values[0] || values[1]); + return globalElablement; } private onInstallExtension(event: InstallExtensionEvent): void { @@ -612,6 +630,7 @@ export class ExtensionsWorkbenchService implements IExtensionsWorkbenchService { const workspaceDisabledExtensions = this.extensionEnablementService.getWorkspaceDisabledExtensions(); extension.disabledGlobally = globallyDisabledExtensions.indexOf(extension.identifier) !== -1; extension.disabledForWorkspace = workspaceDisabledExtensions.indexOf(extension.identifier) !== -1; + this._onChange.fire(); } } diff --git a/src/vs/workbench/parts/extensions/test/browser/extensionsActions.test.ts b/src/vs/workbench/parts/extensions/test/browser/extensionsActions.test.ts new file mode 100644 index 00000000000..6cd2a3992c1 --- /dev/null +++ b/src/vs/workbench/parts/extensions/test/browser/extensionsActions.test.ts @@ -0,0 +1,1135 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import { assign } from 'vs/base/common/objects'; +import { generateUuid } from 'vs/base/common/uuid'; +import { TPromise } from 'vs/base/common/winjs.base'; +import { IExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/common/extensions'; +import * as ExtensionsActions from 'vs/workbench/parts/extensions/browser/extensionsActions'; +import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; +import { + IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, ILocalExtension, LocalExtensionType, IGalleryExtension, + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent +} from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { IURLService } from 'vs/platform/url/common/url'; +import { TestInstantiationService } from 'vs/test/utils/instantiationTestUtils'; +import { Emitter } from 'vs/base/common/event'; +import { IPager } from 'vs/base/common/paging'; +import { ITelemetryService, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IExtensionService } from 'vs/platform/extensions/common/extensions'; + +suite('ExtensionsActions Test', () => { + + let instantiationService: TestInstantiationService; + + let installEvent: Emitter, + didInstallEvent: Emitter, + uninstallEvent: Emitter, + didUninstallEvent: Emitter; + + + suiteSetup(() => { + installEvent = new Emitter(); + didInstallEvent = new Emitter(); + uninstallEvent = new Emitter(); + didUninstallEvent = new Emitter(); + + instantiationService = new TestInstantiationService(); + instantiationService.stub(IURLService, { onOpenURL: new Emitter().event }); + instantiationService.stub(ITelemetryService, NullTelemetryService); + + instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); + + instantiationService.stub(IExtensionManagementService, ExtensionManagementService); + instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event); + instantiationService.stub(IExtensionManagementService, 'onDidInstallExtension', didInstallEvent.event); + instantiationService.stub(IExtensionManagementService, 'onUninstallExtension', uninstallEvent.event); + instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event); + + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + }); + + setup(() => { + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); + instantiationService.stub(IExtensionService, { getExtensions: () => TPromise.wrap([]) }); + (instantiationService.get(IExtensionEnablementService)).reset(); + + instantiationService.set(IExtensionsWorkbenchService, instantiationService.createInstance(ExtensionsWorkbenchService)); + }); + + teardown(() => { + (instantiationService.get(IExtensionsWorkbenchService)).dispose(); + }); + + test('Install action is disabled when there is no extension', () => { + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction); + + assert.ok(!testObject.enabled); + }); + + test('Test Install action when state is installed', (done) => { + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + workbenchService.queryLocal().done(() => { + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id }))); + workbenchService.queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + assert.ok(!testObject.enabled); + assert.equal('Install', testObject.label); + assert.equal('extension-action install', testObject.class); + done(); + }); + }); + }); + + test('Test Install action when state is installing', (done) => { + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + workbenchService.queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + installEvent.fire({ id: gallery.id, gallery }); + + assert.ok(!testObject.enabled); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); + done(); + }); + }); + + test('Test Install action when state is uninstalled', (done) => { + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + workbenchService.queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + assert.ok(testObject.enabled); + assert.equal('Install', testObject.label); + done(); + }); + }); + + test('Test Install action when extension is system action', (done) => { + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction); + const local = aLocalExtension('a', {}, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + uninstallEvent.fire(local.id); + didUninstallEvent.fire({ id: local.id }); + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test Install action when extension doesnot has gallery', (done) => { + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.InstallAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + uninstallEvent.fire(local.id); + didUninstallEvent.fire({ id: local.id }); + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Uninstall action is disabled when there is no extension', () => { + const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction); + + assert.ok(!testObject.enabled); + }); + + test('Test Uninstall action when state is uninstalling', (done) => { + const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + uninstallEvent.fire(local.id); + assert.ok(!testObject.enabled); + assert.equal('Uninstalling', testObject.label); + assert.equal('extension-action uninstall uninstalling', testObject.class); + done(); + }); + }); + + test('Test Uninstall action when state is installed and is user extension', (done) => { + const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Uninstall', testObject.label); + assert.equal('extension-action uninstall', testObject.class); + done(); + }); + }); + + test('Test Uninstall action when state is installed and is system extension', (done) => { + const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction); + const local = aLocalExtension('a', {}, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + assert.equal('Uninstall', testObject.label); + assert.equal('extension-action uninstall', testObject.class); + done(); + }); + }); + + test('Test Uninstall action after extension is installed', (done) => { + const testObject: ExtensionsActions.UninstallAction = instantiationService.createInstance(ExtensionsActions.UninstallAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(paged => { + testObject.extension = paged.firstPage[0]; + + installEvent.fire({ id: gallery.id, gallery }); + didInstallEvent.fire({ id: gallery.id, gallery, local: aLocalExtension('a', gallery, gallery) }); + + assert.ok(testObject.enabled); + assert.equal('Uninstall', testObject.label); + assert.equal('extension-action uninstall', testObject.class); + done(); + }); + }); + + test('Test CombinedInstallAction when there is no extension', () => { + const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction); + + assert.ok(!testObject.enabled); + assert.equal('extension-action install no-extension', testObject.class); + }); + + test('Test CombinedInstallAction when extension is system extension', (done) => { + const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction); + const local = aLocalExtension('a', {}, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + assert.equal('extension-action install no-extension', testObject.class); + done(); + }); + }); + + test('Test CombinedInstallAction when installAction is enabled', (done) => { + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + workbenchService.queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + assert.ok(testObject.enabled); + assert.equal('Install', testObject.label); + assert.equal('extension-action install', testObject.class); + done(); + }); + }); + + test('Test CombinedInstallAction when unInstallAction is enabled', (done) => { + const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('Uninstall', testObject.label); + assert.equal('extension-action uninstall', testObject.class); + done(); + }); + }); + + test('Test CombinedInstallAction when state is installing', (done) => { + const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + workbenchService.queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + installEvent.fire({ id: gallery.id, gallery }); + + assert.ok(!testObject.enabled); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); + done(); + }); + }); + + test('Test CombinedInstallAction when state is uninstalling', (done) => { + const testObject: ExtensionsActions.CombinedInstallAction = instantiationService.createInstance(ExtensionsActions.CombinedInstallAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + uninstallEvent.fire(local.id); + assert.ok(!testObject.enabled); + assert.equal('Uninstalling', testObject.label); + assert.equal('extension-action uninstall uninstalling', testObject.class); + done(); + }); + }); + + test('Test UpdateAction when there is no extension', () => { + const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction); + + assert.ok(!testObject.enabled); + }); + + test('Test UpdateAction when extension is uninstalled', (done) => { + const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction); + const gallery = aGalleryExtension('a', { version: '1.0.0' }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test UpdateAction when extension is installed and not outdated', (done) => { + const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction); + const local = aLocalExtension('a', { version: '1.0.0' }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {id: local.id, version: local.manifest.version}))); + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { + assert.ok(!testObject.enabled); + done(); + }); + }); + }); + + test('Test UpdateAction when extension is installed outdated and system extension', (done) => { + const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction); + const local = aLocalExtension('a', { version: '1.0.0' }, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: '1.0.1' }))); + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { + assert.ok(!testObject.enabled); + done(); + }); + }); + }); + + test('Test UpdateAction when extension is installed outdated and user extension', (done) => { + const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction); + const local = aLocalExtension('a', { version: '1.0.0' }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local.id, version: '1.0.1' }))); + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { + assert.ok(testObject.enabled); + done(); + }); + }); + }); + + test('Test UpdateAction when extension is installing and outdated and user extension', (done) => { + const testObject: ExtensionsActions.UpdateAction = instantiationService.createInstance(ExtensionsActions.UpdateAction); + const local = aLocalExtension('a', { version: '1.0.0' }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.1' }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(extensions => { + installEvent.fire({ id: local.id, gallery }); + assert.ok(!testObject.enabled); + done(); + }); + }); + }); + + test('Test ManageExtensionAction when there is no extension', () => { + const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction); + + assert.ok(!testObject.enabled); + }); + + test('Test ManageExtensionAction when extension is installed', (done) => { + const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + assert.equal('extension-action manage', testObject.class); + assert.equal('', testObject.tooltip); + + done(); + }); + }); + + test('Test ManageExtensionAction when extension is uninstalled', (done) => { + const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { + testObject.extension = page.firstPage[0]; + assert.ok(!testObject.enabled); + assert.equal('extension-action manage no-extension', testObject.class); + assert.equal('', testObject.tooltip); + + done(); + }); + }); + + test('Test ManageExtensionAction when extension is installing', (done) => { + const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { + testObject.extension = page.firstPage[0]; + + installEvent.fire({ id: gallery.id, gallery }); + assert.ok(!testObject.enabled); + assert.equal('extension-action manage no-extension', testObject.class); + assert.equal('', testObject.tooltip); + + done(); + }); + }); + + test('Test ManageExtensionAction when extension is uninstalling', (done) => { + const testObject: ExtensionsActions.ManageExtensionAction = instantiationService.createInstance(ExtensionsActions.ManageExtensionAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + uninstallEvent.fire(local.id); + + assert.ok(!testObject.enabled); + assert.equal('extension-action manage', testObject.class); + assert.equal('Uninstalling', testObject.tooltip); + + done(); + }); + }); + + test('Test EnableForWorkspaceAction when there is no extension', () => { + const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); + + assert.ok(!testObject.enabled); + }); + + test('Test EnableForWorkspaceAction when there extension is not disabled', (done) => { + const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test EnableForWorkspaceAction when there extension is disabled globally', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test EnableForWorkspaceAction when extension is disabled for workspace', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + done(); + }); + }); + + test('Test EnableForWorkspaceAction when the extension is disabled in both', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + const testObject: ExtensionsActions.EnableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.EnableForWorkspaceAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test EnableGloballyAction when there is no extension', () => { + const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); + + assert.ok(!testObject.enabled); + }); + + test('Test EnableGloballyAction when the extension is not disabled', (done) => { + const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test EnableGloballyAction when the extension is disabled for workspace', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test EnableGloballyAction when the extension is disabled globally', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + done(); + }); + }); + + test('Test EnableGloballyAction when the extension is disabled in both', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + const testObject: ExtensionsActions.EnableGloballyAction = instantiationService.createInstance(ExtensionsActions.EnableGloballyAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + done(); + }); + }); + + test('Test EnableAction when there is no extension', () => { + const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); + + assert.ok(!testObject.enabled); + }); + + test('Test EnableAction when extension is installed and enabled', (done) => { + const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test EnableAction when extension is installed and disabled globally', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + done(); + }); + }); + + test('Test EnableAction when extension is installed and disabled for workspace', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + done(); + }); + }); + + test('Test EnableAction when extension is uninstalled', (done) => { + const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { + testObject.extension = page.firstPage[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test EnableAction when extension is installing', (done) => { + const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { + testObject.extension = page.firstPage[0]; + + installEvent.fire({ id: gallery.id, gallery }); + assert.ok(!testObject.enabled); + + done(); + }); + }); + + test('Test EnableAction when extension is uninstalling', (done) => { + const testObject: ExtensionsActions.EnableAction = instantiationService.createInstance(ExtensionsActions.EnableAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + uninstallEvent.fire(local.id); + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test DisableForWorkspaceAction when there is no extension', () => { + const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); + + assert.ok(!testObject.enabled); + }); + + test('Test DisableForWorkspaceAction when the extension is disabled globally', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test DisableForWorkspaceAction when the extension is disabled workspace', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test DisableForWorkspaceAction when extension is enabled', (done) => { + const testObject: ExtensionsActions.DisableForWorkspaceAction = instantiationService.createInstance(ExtensionsActions.DisableForWorkspaceAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + done(); + }); + }); + + test('Test DisableGloballyAction when there is no extension', () => { + const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); + + assert.ok(!testObject.enabled); + }); + + test('Test DisableGloballyAction when the extension is disabled globally', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test DisableGloballyAction when the extension is disabled for workspace', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test DisableGloballyAction when the extension is enabled', (done) => { + const testObject: ExtensionsActions.DisableGloballyAction = instantiationService.createInstance(ExtensionsActions.DisableGloballyAction, 'id'); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + done(); + }); + }); + + test('Test DisableAction when there is no extension', () => { + const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); + + assert.ok(!testObject.enabled); + }); + + test('Test DisableAction when extension is installed and enabled', (done) => { + const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(testObject.enabled); + done(); + }); + }); + + test('Test DisableAction when extension is installed and disabled globally', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test DisableAction when extension is installed and disabled for workspace', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test DisableAction when extension is uninstalled', (done) => { + const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { + testObject.extension = page.firstPage[0]; + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test DisableAction when extension is installing', (done) => { + const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done(page => { + testObject.extension = page.firstPage[0]; + + installEvent.fire({ id: gallery.id, gallery }); + assert.ok(!testObject.enabled); + + done(); + }); + }); + + test('Test DisableAction when extension is uninstalling', (done) => { + const testObject: ExtensionsActions.DisableAction = instantiationService.createInstance(ExtensionsActions.DisableAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + uninstallEvent.fire(local.id); + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test UpdateAllAction when no installed extensions', () => { + const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); + + assert.ok(!testObject.enabled); + }); + + test('Test UpdateAllAction when installed extensions are not outdated', (done) => { + const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a'), aLocalExtension('b')]); + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test UpdateAllAction when some installed extensions are outdated', (done) => { + const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); + const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); + workbenchService.queryLocal().done(() => { + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local))); + workbenchService.queryGallery().done(() => { + assert.ok(testObject.enabled); + done(); + }); + }); + }); + + test('Test UpdateAllAction when some installed extensions are outdated and some outdated are being installed', (done) => { + const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); + const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; + const gallery = [aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local)]; + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); + workbenchService.queryLocal().done(() => { + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery)); + workbenchService.queryGallery().done(() => { + installEvent.fire({ id: local[0].id, gallery: gallery[0] }); + assert.ok(testObject.enabled); + done(); + }); + }); + }); + + test('Test UpdateAllAction when some installed extensions are outdated and all outdated are being installed', (done) => { + const testObject: ExtensionsActions.UpdateAllAction = instantiationService.createInstance(ExtensionsActions.UpdateAllAction, 'id', 'label'); + const local = [aLocalExtension('a', { version: '1.0.1' }), aLocalExtension('b', { version: '1.0.1' }), aLocalExtension('c', { version: '1.0.1' })]; + const gallery = [aGalleryExtension('a', { id: local[0].id, version: '1.0.2' }), aGalleryExtension('b', { id: local[1].id, version: '1.0.2' }), aGalleryExtension('c', local)]; + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', local); + workbenchService.queryLocal().done(() => { + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(...gallery)); + workbenchService.queryGallery().done(() => { + installEvent.fire({ id: local[0].id, gallery: gallery[0] }); + installEvent.fire({ id: local[1].id, gallery: gallery[1] }); + assert.ok(!testObject.enabled); + done(); + }); + }); + }); + + test('Test ReloadAction when there is no extension', () => { + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + + assert.ok(!testObject.enabled); + }); + + test('Test ReloadAction when extension state is installing', (done) => { + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + workbenchService.queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + installEvent.fire({ id: gallery.id, gallery }); + + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test ReloadAction when extension state is uninstalling', (done) => { + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + uninstallEvent.fire(local.id); + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test ReloadAction when extension is newly installed', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + installEvent.fire({ id: gallery.id, gallery }); + didInstallEvent.fire({ id: gallery.id, gallery, local: aLocalExtension('a', gallery, gallery) }); + + assert.ok(testObject.enabled); + assert.equal('Reload to activate', testObject.tooltip); + assert.equal(`Reload this window to activate the extension 'a'?`, testObject.reloadMessaage); + done(); + }); + }); + + test('Test ReloadAction when extension is installed and uninstalled', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const gallery = aGalleryExtension('a'); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + instantiationService.get(IExtensionsWorkbenchService).queryGallery().done((paged) => { + testObject.extension = paged.firstPage[0]; + installEvent.fire({ id: gallery.id, gallery }); + didInstallEvent.fire({ id: gallery.id, gallery, local: aLocalExtension('a', gallery, gallery) }); + uninstallEvent.fire(gallery.id); + didUninstallEvent.fire({ id: gallery.id }); + + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test ReloadAction when extension is uninstalled', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.a' }]); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + uninstallEvent.fire(local.id); + didUninstallEvent.fire({ id: local.id }); + + assert.ok(testObject.enabled); + assert.equal('Reload to deactivate', testObject.tooltip); + assert.equal(`Reload this window to deactivate the uninstalled extension 'a'?`, testObject.reloadMessaage); + done(); + }); + }); + + test('Test ReloadAction when extension is uninstalled and installed', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.a' }]); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a'); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + instantiationService.get(IExtensionsWorkbenchService).queryLocal().done(extensions => { + testObject.extension = extensions[0]; + uninstallEvent.fire(local.id); + didUninstallEvent.fire({ id: local.id }); + const gallery = aGalleryExtension('a', { id: local.id }); + installEvent.fire({ id: local.id, gallery }); + didInstallEvent.fire({ id: gallery.id, gallery, local }); + + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test ReloadAction when extension is updated while running', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.a', version: '1.0.1' }]); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a', { version: '1.0.1' }); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + workbenchService.queryLocal().done(extensions => { + testObject.extension = extensions[0]; + + const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); + installEvent.fire({ id: gallery.id, gallery }); + didInstallEvent.fire({ id: gallery.id, gallery, local: aLocalExtension('a', gallery, gallery) }); + + assert.ok(testObject.enabled); + assert.equal('Reload to update', testObject.tooltip); + assert.equal(`Reload this window to activate the updated extension 'a'?`, testObject.reloadMessaage); + done(); + + }); + }); + + test('Test ReloadAction when extension is updated when not running', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a', { version: '1.0.1' }); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + workbenchService.queryLocal().done(extensions => { + testObject.extension = extensions[0]; + + const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); + installEvent.fire({ id: gallery.id, gallery }); + didInstallEvent.fire({ id: gallery.id, gallery, local: aLocalExtension('a', gallery, gallery) }); + + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test ReloadAction when extension is disabled when running', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.a' }]); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a'); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + workbenchService.queryLocal().done(extensions => { + testObject.extension = extensions[0]; + workbenchService.setEnablement(extensions[0], false); + + assert.ok(testObject.enabled); + assert.equal('Reload to deactivate', testObject.tooltip); + assert.equal(`Reload this window to deactivate the extension 'a'?`, testObject.reloadMessaage); + done(); + }); + }); + + test('Test ReloadAction when extension enablement is toggled when running', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.a' }]); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a'); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + workbenchService.queryLocal().done(extensions => { + testObject.extension = extensions[0]; + workbenchService.setEnablement(extensions[0], false); + workbenchService.setEnablement(extensions[0], true); + + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test ReloadAction when extension is enabled when not running', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a'); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + workbenchService.queryLocal().done(extensions => { + testObject.extension = extensions[0]; + workbenchService.setEnablement(extensions[0], true); + + assert.ok(testObject.enabled); + assert.equal('Reload to activate', testObject.tooltip); + assert.equal(`Reload this window to activate the extension 'a'?`, testObject.reloadMessaage); + done(); + }); + }); + + test('Test ReloadAction when extension enablement is toggled when not running', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a'); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + workbenchService.queryLocal().done(extensions => { + testObject.extension = extensions[0]; + workbenchService.setEnablement(extensions[0], true); + workbenchService.setEnablement(extensions[0], false); + + assert.ok(!testObject.enabled); + done(); + }); + }); + + test('Test ReloadAction when extension is updated when not running and enabled', (done) => { + instantiationService.stubPromise(IExtensionService, 'getExtensions', [{ id: 'pub.b' }]); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + const local = aLocalExtension('a', { version: '1.0.1' }); + const workbenchService = instantiationService.get(IExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + workbenchService.queryLocal().done(extensions => { + testObject.extension = extensions[0]; + + const gallery = aGalleryExtension('a', { id: local.id, version: '1.0.2' }); + installEvent.fire({ id: gallery.id, gallery }); + didInstallEvent.fire({ id: gallery.id, gallery, local: aLocalExtension('a', gallery, gallery) }); + workbenchService.setEnablement(extensions[0], true); + + assert.ok(testObject.enabled); + assert.equal('Reload to activate', testObject.tooltip); + assert.equal(`Reload this window to activate the extension 'a'?`, testObject.reloadMessaage); + done(); + }); + }); + + function aLocalExtension(name: string = 'someext', manifest: any = {}, properties: any = {}): ILocalExtension { + const localExtension = Object.create({ manifest: {} }); + assign(localExtension, { type: LocalExtensionType.User, id: generateUuid() }, properties); + assign(localExtension.manifest, { name, publisher: 'pub' }, manifest); + localExtension.metadata = { id: localExtension.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; + return localExtension; + } + + function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: any = {}): IGalleryExtension { + const galleryExtension = Object.create({}); + assign(galleryExtension, { name, publisher: 'pub', id: generateUuid(), properties: {}, assets: {} }, properties); + assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); + assign(galleryExtension.assets, assets); + return galleryExtension; + } + + function aPage(...objects: T[]): IPager { + return { firstPage: objects, total: objects.length, pageSize: objects.length, getPage: () => null }; + } + +}); \ No newline at end of file diff --git a/src/vs/workbench/parts/extensions/test/common/extensionQuery.test.ts b/src/vs/workbench/parts/extensions/test/common/extensionQuery.test.ts index 63a8d724082..865a5173018 100644 --- a/src/vs/workbench/parts/extensions/test/common/extensionQuery.test.ts +++ b/src/vs/workbench/parts/extensions/test/common/extensionQuery.test.ts @@ -6,7 +6,7 @@ 'use strict'; import * as assert from 'assert'; -import { Query } from '../../common/extensionQuery'; +import { Query } from 'vs/workbench/parts/extensions/common/extensionQuery'; suite('Extension query', () => { test('parse', () => { diff --git a/src/vs/workbench/parts/extensions/test/node/extensionsWorkbenchService.test.ts b/src/vs/workbench/parts/extensions/test/node/extensionsWorkbenchService.test.ts new file mode 100644 index 00000000000..c2973c189a1 --- /dev/null +++ b/src/vs/workbench/parts/extensions/test/node/extensionsWorkbenchService.test.ts @@ -0,0 +1,855 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as sinon from 'sinon'; +import * as assert from 'assert'; +import * as fs from 'fs'; +import { assign } from 'vs/base/common/objects'; +import { generateUuid } from 'vs/base/common/uuid'; +import { IExtensionsWorkbenchService, ExtensionState } from 'vs/workbench/parts/extensions/common/extensions'; +import { ExtensionsWorkbenchService } from 'vs/workbench/parts/extensions/node/extensionsWorkbenchService'; +import { + IExtensionManagementService, IExtensionGalleryService, IExtensionEnablementService, ILocalExtension, LocalExtensionType, IGalleryExtension, + DidInstallExtensionEvent, DidUninstallExtensionEvent, InstallExtensionEvent +} from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; +import { TestExtensionEnablementService } from 'vs/platform/extensionManagement/test/common/extensionEnablementService.test'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { IURLService } from 'vs/platform/url/common/url'; +import { TestInstantiationService } from 'vs/test/utils/instantiationTestUtils'; +import Event, { Emitter } from 'vs/base/common/event'; +import { IPager } from 'vs/base/common/paging'; +import { ITelemetryService, NullTelemetryService } from 'vs/platform/telemetry/common/telemetry'; + +suite('ExtensionsWorkbenchService Test', () => { + + let instantiationService: TestInstantiationService; + let testObject: IExtensionsWorkbenchService; + + let installEvent: Emitter, + didInstallEvent: Emitter, + uninstallEvent: Emitter, + didUninstallEvent: Emitter; + + suiteSetup(() => { + installEvent = new Emitter(); + didInstallEvent = new Emitter(); + uninstallEvent = new Emitter(); + didUninstallEvent = new Emitter(); + + instantiationService = new TestInstantiationService(); + instantiationService.stub(IURLService, { onOpenURL: new Emitter().event }); + instantiationService.stub(ITelemetryService, NullTelemetryService); + + instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); + + instantiationService.stub(IExtensionManagementService, ExtensionManagementService); + instantiationService.stub(IExtensionManagementService, 'onInstallExtension', installEvent.event); + instantiationService.stub(IExtensionManagementService, 'onDidInstallExtension', didInstallEvent.event); + instantiationService.stub(IExtensionManagementService, 'onUninstallExtension', uninstallEvent.event); + instantiationService.stub(IExtensionManagementService, 'onDidUninstallExtension', didUninstallEvent.event); + + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + }); + + setup(() => { + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', []); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage()); + (instantiationService.get(IExtensionEnablementService)).reset(); + }); + + teardown(() => { + (testObject).dispose(); + }); + + test('test gallery extension', (done) => { + const expected = aGalleryExtension('expectedName', { + displayName: 'expectedDisplayName', + version: '1.5', + publisherId: 'expectedPublisherId', + publisher: 'expectedPublisher', + publisherDisplayName: 'expectedPublisherDisplayName', + description: 'expectedDescription', + installCount: 1000, + rating: 4, + ratingCount: 100 + }, { + dependencies: ['pub.1', 'pub.2'], + }, { + manifest: 'expectedMainfest', + readme: 'expectedReadme', + changeLog: 'expectedChangelog', + download: 'expectedDownload', + icon: 'expectedIcon', + iconFallback: 'expectedIconFallback', + license: 'expectedLicense' + }); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(expected)); + testObject.queryGallery().done(pagedResponse => { + assert.equal(1, pagedResponse.firstPage.length); + const actual = pagedResponse.firstPage[0]; + + assert.equal(null, actual.type); + assert.equal('expectedName', actual.name); + assert.equal('expectedDisplayName', actual.displayName); + assert.equal('expectedPublisher.expectedName', actual.identifier); + assert.equal('expectedPublisher', actual.publisher); + assert.equal('expectedPublisherDisplayName', actual.publisherDisplayName); + assert.equal('1.5', actual.version); + assert.equal('1.5', actual.latestVersion); + assert.equal('expectedDescription', actual.description); + assert.equal('expectedIcon', actual.iconUrl); + assert.equal('expectedIconFallback', actual.iconUrlFallback); + assert.equal('expectedLicense', actual.licenseUrl); + assert.equal(ExtensionState.Uninstalled, actual.state); + assert.equal(1000, actual.installCount); + assert.equal(4, actual.rating); + assert.equal(100, actual.ratingCount); + assert.equal(false, actual.outdated); + assert.deepEqual(['pub.1', 'pub.2'], actual.dependencies); + done(); + }); + }); + + test('test for empty installed extensions', () => { + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + assert.deepEqual([], testObject.local); + }); + + test('test for installed extensions', () => { + const expected1 = aLocalExtension('local1', { + publisher: 'localPublisher1', + version: '1.1', + displayName: 'localDisplayName1', + description: 'localDescription1', + icon: 'localIcon1', + extensionDependencies: ['pub.1', 'pub.2'], + }, { + type: LocalExtensionType.User, + readmeUrl: 'localReadmeUrl1', + changelogUrl: 'localChangelogUrl1', + path: 'localPath1' + }); + const expected2 = aLocalExtension('local2', { + publisher: 'localPublisher2', + version: '1.2', + displayName: 'localDisplayName2', + description: 'localDescription2', + }, { + type: LocalExtensionType.System, + readmeUrl: 'localReadmeUrl2', + changelogUrl: 'localChangelogUrl2', + }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [expected1, expected2]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + const actuals = testObject.local; + assert.equal(2, actuals.length); + + let actual = actuals[0]; + assert.equal(LocalExtensionType.User, actual.type); + assert.equal('local1', actual.name); + assert.equal('localDisplayName1', actual.displayName); + assert.equal('localPublisher1.local1', actual.identifier); + assert.equal('localPublisher1', actual.publisher); + assert.equal('1.1', actual.version); + assert.equal('1.1', actual.latestVersion); + assert.equal('localDescription1', actual.description); + assert.equal('file:///localPath1/localIcon1', actual.iconUrl); + assert.equal('file:///localPath1/localIcon1', actual.iconUrlFallback); + assert.equal(null, actual.licenseUrl); + assert.equal(ExtensionState.Installed, actual.state); + assert.equal(null, actual.installCount); + assert.equal(null, actual.rating); + assert.equal(null, actual.ratingCount); + assert.equal(false, actual.outdated); + assert.deepEqual(['pub.1', 'pub.2'], actual.dependencies); + + actual = actuals[1]; + assert.equal(LocalExtensionType.System, actual.type); + assert.equal('local2', actual.name); + assert.equal('localDisplayName2', actual.displayName); + assert.equal('localPublisher2.local2', actual.identifier); + assert.equal('localPublisher2', actual.publisher); + assert.equal('1.2', actual.version); + assert.equal('1.2', actual.latestVersion); + assert.equal('localDescription2', actual.description); + assert.ok(fs.existsSync(actual.iconUrl)); + assert.equal(null, actual.licenseUrl); + assert.equal(ExtensionState.Installed, actual.state); + assert.equal(null, actual.installCount); + assert.equal(null, actual.rating); + assert.equal(null, actual.ratingCount); + assert.equal(false, actual.outdated); + assert.deepEqual([], actual.dependencies); + }); + + test('test installed extensions get syncs with gallery', (done) => { + const local1 = aLocalExtension('local1', { + publisher: 'localPublisher1', + version: '1.1.0', + displayName: 'localDisplayName1', + description: 'localDescription1', + icon: 'localIcon1', + extensionDependencies: ['pub.1', 'pub.2'], + }, { + type: LocalExtensionType.User, + readmeUrl: 'localReadmeUrl1', + changelogUrl: 'localChangelogUrl1', + path: 'localPath1' + }); + const local2 = aLocalExtension('local2', { + publisher: 'localPublisher2', + version: '1.2.0', + displayName: 'localDisplayName2', + description: 'localDescription2', + }, { + type: LocalExtensionType.System, + readmeUrl: 'localReadmeUrl2', + changelogUrl: 'localChangelogUrl2', + }); + const gallery1 = aGalleryExtension('expectedName', { + id: local1.id, + displayName: 'expectedDisplayName', + version: '1.5.0', + publisherId: 'expectedPublisherId', + publisher: 'expectedPublisher', + publisherDisplayName: 'expectedPublisherDisplayName', + description: 'expectedDescription', + installCount: 1000, + rating: 4, + ratingCount: 100 + }, { + dependencies: ['pub.1'], + }, { + manifest: 'expectedMainfest', + readme: 'expectedReadme', + changeLog: 'expectedChangelog', + download: 'expectedDownload', + icon: 'expectedIcon', + iconFallback: 'expectedIconFallback', + license: 'expectedLicense' + }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local1, local2]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery1)); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + listenAfter(testObject.onChange)(() => { + const actuals = testObject.local; + assert.equal(2, actuals.length); + + let actual = actuals[0]; + assert.equal(LocalExtensionType.User, actual.type); + assert.equal('local1', actual.name); + assert.equal('localDisplayName1', actual.displayName); + assert.equal('localPublisher1.local1', actual.identifier); + assert.equal('localPublisher1', actual.publisher); + assert.equal('1.1.0', actual.version); + assert.equal('1.5.0', actual.latestVersion); + assert.equal('localDescription1', actual.description); + assert.equal('file:///localPath1/localIcon1', actual.iconUrl); + assert.equal('file:///localPath1/localIcon1', actual.iconUrlFallback); + assert.equal(ExtensionState.Installed, actual.state); + assert.equal('expectedLicense', actual.licenseUrl); + assert.equal(1000, actual.installCount); + assert.equal(4, actual.rating); + assert.equal(100, actual.ratingCount); + assert.equal(true, actual.outdated); + assert.deepEqual(['pub.1', 'pub.2'], actual.dependencies); + + actual = actuals[1]; + assert.equal(LocalExtensionType.System, actual.type); + assert.equal('local2', actual.name); + assert.equal('localDisplayName2', actual.displayName); + assert.equal('localPublisher2.local2', actual.identifier); + assert.equal('localPublisher2', actual.publisher); + assert.equal('1.2.0', actual.version); + assert.equal('1.2.0', actual.latestVersion); + assert.equal('localDescription2', actual.description); + assert.ok(fs.existsSync(actual.iconUrl)); + assert.equal(null, actual.licenseUrl); + assert.equal(ExtensionState.Installed, actual.state); + assert.equal(null, actual.installCount); + assert.equal(null, actual.rating); + assert.equal(null, actual.ratingCount); + assert.equal(false, actual.outdated); + assert.deepEqual([], actual.dependencies); + done(); + }); + }); + + test('test extension state computation', (done) => { + const gallery = aGalleryExtension('gallery1'); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + + testObject.queryGallery().done(page => { + const extension = page.firstPage[0]; + assert.equal(ExtensionState.Uninstalled, extension.state); + + testObject.install(extension); + + // Installing + installEvent.fire({ id: gallery.id, gallery }); + let local = testObject.local; + assert.equal(1, local.length); + const actual = local[0]; + assert.equal(`${gallery.publisher}.${gallery.name}`, actual.identifier); + assert.equal(ExtensionState.Installing, actual.state); + + // Installed + didInstallEvent.fire({ id: gallery.id, gallery, local: aLocalExtension(gallery.name, gallery, gallery) }); + assert.equal(ExtensionState.Installed, actual.state); + assert.equal(1, testObject.local.length); + + testObject.uninstall(actual); + + // Uninstalling + uninstallEvent.fire(gallery.id); + assert.equal(ExtensionState.Uninstalling, actual.state); + + // Uninstalled + didUninstallEvent.fire({ id: gallery.id }); + assert.equal(ExtensionState.Uninstalled, actual.state); + + assert.equal(0, testObject.local.length); + done(); + }); + }); + + test('test extension doesnot show outdated for system extensions', () => { + const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id, version: '1.0.2' }))); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + assert.ok(!testObject.local[0].outdated); + }); + + test('test canInstall returns false for extensions with out gallery', () => { + const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + const target = testObject.local[0]; + testObject.uninstall(target); + uninstallEvent.fire(local.id); + didUninstallEvent.fire({ id: local.id }); + + assert.ok(!testObject.canInstall(target)); + }); + + test('test canInstall returns true for extensions with gallery', (done) => { + const local = aLocalExtension('a', { version: '1.0.1' }, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension(local.manifest.name, { id: local.id }))); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + const target = testObject.local[0]; + + listenAfter(testObject.onChange)(() => { + assert.ok(testObject.canInstall(target)); + done(); + }); + }); + + test('test onchange event is triggered while installing', (done) => { + const gallery = aGalleryExtension('gallery1'); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + const target = sinon.spy(); + + testObject.queryGallery().done(page => { + const extension = page.firstPage[0]; + assert.equal(ExtensionState.Uninstalled, extension.state); + + testObject.install(extension); + installEvent.fire({ id: gallery.id, gallery }); + testObject.onChange(target); + + // Installed + didInstallEvent.fire({ id: gallery.id, gallery, local: aLocalExtension(gallery.name, gallery, gallery) }); + + assert.ok(target.calledOnce); + done(); + }); + }); + + test('test onchange event is triggered when installation is finished', (done) => { + const gallery = aGalleryExtension('gallery1'); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); + const target = sinon.spy(); + + testObject.queryGallery().done(page => { + const extension = page.firstPage[0]; + assert.equal(ExtensionState.Uninstalled, extension.state); + + testObject.install(extension); + testObject.onChange(target); + + // Installing + installEvent.fire({ id: gallery.id, gallery }); + + assert.ok(target.calledOnce); + done(); + }); + }); + + test('test onchange event is triggered while uninstalling', () => { + const local = aLocalExtension('a', {}, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + const target = sinon.spy(); + + testObject.uninstall(testObject.local[0]); + testObject.onChange(target); + uninstallEvent.fire(local.id); + + assert.ok(target.calledOnce); + }); + + test('test onchange event is triggered when uninstalling is finished', () => { + const local = aLocalExtension('a', {}, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + const target = sinon.spy(); + + testObject.uninstall(testObject.local[0]); + uninstallEvent.fire(local.id); + testObject.onChange(target); + didUninstallEvent.fire({ id: local.id }); + + assert.ok(target.calledOnce); + }); + + test('test extension dependencies when empty', (done) => { + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); + + testObject.queryGallery().done(page => { + testObject.loadDependencies(page.firstPage[0]).done(dependencies => { + assert.equal(null, dependencies); + done(); + }); + }); + }); + + test('test one level extension dependencies without cycle', (done) => { + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.b', 'pub.c', 'pub.d'] }))); + instantiationService.stubPromise(IExtensionGalleryService, 'getAllDependencies', [aGalleryExtension('b'), aGalleryExtension('c'), aGalleryExtension('d')]); + + testObject.queryGallery().done(page => { + const extension = page.firstPage[0]; + testObject.loadDependencies(extension).done(actual => { + assert.ok(actual.hasDependencies); + assert.equal(extension, actual.extension); + assert.equal(null, actual.dependent); + assert.equal(3, actual.dependencies.length); + assert.equal('pub.a', actual.identifier); + let dependent = actual; + + actual = dependent.dependencies[0]; + assert.ok(!actual.hasDependencies); + assert.equal('pub.b', actual.extension.identifier); + assert.equal('pub.b', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + + actual = dependent.dependencies[1]; + assert.ok(!actual.hasDependencies); + assert.equal('pub.c', actual.extension.identifier); + assert.equal('pub.c', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + + actual = dependent.dependencies[2]; + assert.ok(!actual.hasDependencies); + assert.equal('pub.d', actual.extension.identifier); + assert.equal('pub.d', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + done(); + }); + }); + }); + + test('test one level extension dependencies with cycle', (done) => { + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.b', 'pub.a'] }))); + instantiationService.stubPromise(IExtensionGalleryService, 'getAllDependencies', [aGalleryExtension('b'), aGalleryExtension('a')]); + + testObject.queryGallery().done(page => { + const extension = page.firstPage[0]; + testObject.loadDependencies(extension).done(actual => { + assert.ok(actual.hasDependencies); + assert.equal(extension, actual.extension); + assert.equal(null, actual.dependent); + assert.equal(2, actual.dependencies.length); + assert.equal('pub.a', actual.identifier); + let dependent = actual; + + actual = dependent.dependencies[0]; + assert.ok(!actual.hasDependencies); + assert.equal('pub.b', actual.extension.identifier); + assert.equal('pub.b', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + + actual = dependent.dependencies[1]; + assert.ok(!actual.hasDependencies); + assert.equal('pub.a', actual.extension.identifier); + assert.equal('pub.a', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + + done(); + }); + }); + }); + + test('test one level extension dependencies with missing dependencies', (done) => { + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.b', 'pub.a'] }))); + instantiationService.stubPromise(IExtensionGalleryService, 'getAllDependencies', [aGalleryExtension('a')]); + + testObject.queryGallery().done(page => { + const extension = page.firstPage[0]; + testObject.loadDependencies(extension).done(actual => { + assert.ok(actual.hasDependencies); + assert.equal(extension, actual.extension); + assert.equal(null, actual.dependent); + assert.equal(2, actual.dependencies.length); + assert.equal('pub.a', actual.identifier); + let dependent = actual; + + actual = dependent.dependencies[0]; + assert.ok(!actual.hasDependencies); + assert.equal(null, actual.extension); + assert.equal('pub.b', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + + actual = dependent.dependencies[1]; + assert.ok(!actual.hasDependencies); + assert.equal('pub.a', actual.extension.identifier); + assert.equal('pub.a', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + + done(); + }); + }); + }); + + test('test one level extension dependencies with in built dependencies', (done) => { + const local = aLocalExtension('inbuilt', {}, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.inbuilt', 'pub.a'] }))); + instantiationService.stubPromise(IExtensionGalleryService, 'getAllDependencies', [aGalleryExtension('a')]); + + testObject.queryGallery().done(page => { + const extension = page.firstPage[0]; + testObject.loadDependencies(extension).done(actual => { + assert.ok(actual.hasDependencies); + assert.equal(extension, actual.extension); + assert.equal(null, actual.dependent); + assert.equal(2, actual.dependencies.length); + assert.equal('pub.a', actual.identifier); + let dependent = actual; + + actual = dependent.dependencies[0]; + assert.ok(!actual.hasDependencies); + assert.equal('pub.inbuilt', actual.extension.identifier); + assert.equal('pub.inbuilt', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + + + actual = dependent.dependencies[1]; + assert.ok(!actual.hasDependencies); + assert.equal('pub.a', actual.extension.identifier); + assert.equal('pub.a', actual.identifier); + assert.equal(dependent, actual.dependent); + assert.equal(0, actual.dependencies.length); + + done(); + }); + }); + }); + + test('test more than one level of extension dependencies', (done) => { + const local = aLocalExtension('c', { extensionDependencies: ['pub.d'] }, { type: LocalExtensionType.System }); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', {}, { dependencies: ['pub.b', 'pub.c'] }))); + instantiationService.stubPromise(IExtensionGalleryService, 'getAllDependencies', [ + aGalleryExtension('b', {}, { dependencies: ['pub.d', 'pub.e'] }), + aGalleryExtension('d', {}, { dependencies: ['pub.f', 'pub.c'] }), + aGalleryExtension('e')]); + + testObject.queryGallery().done(page => { + const extension = page.firstPage[0]; + testObject.loadDependencies(extension).done(a => { + assert.ok(a.hasDependencies); + assert.equal(extension, a.extension); + assert.equal(null, a.dependent); + assert.equal(2, a.dependencies.length); + assert.equal('pub.a', a.identifier); + + let b = a.dependencies[0]; + assert.ok(b.hasDependencies); + assert.equal('pub.b', b.extension.identifier); + assert.equal('pub.b', b.identifier); + assert.equal(a, b.dependent); + assert.equal(2, b.dependencies.length); + + let c = a.dependencies[1]; + assert.ok(c.hasDependencies); + assert.equal('pub.c', c.extension.identifier); + assert.equal('pub.c', c.identifier); + assert.equal(a, c.dependent); + assert.equal(1, c.dependencies.length); + + let d = b.dependencies[0]; + assert.ok(d.hasDependencies); + assert.equal('pub.d', d.extension.identifier); + assert.equal('pub.d', d.identifier); + assert.equal(b, d.dependent); + assert.equal(2, d.dependencies.length); + + let e = b.dependencies[1]; + assert.ok(!e.hasDependencies); + assert.equal('pub.e', e.extension.identifier); + assert.equal('pub.e', e.identifier); + assert.equal(b, e.dependent); + assert.equal(0, e.dependencies.length); + + let f = d.dependencies[0]; + assert.ok(!f.hasDependencies); + assert.equal(null, f.extension); + assert.equal('pub.f', f.identifier); + assert.equal(d, f.dependent); + assert.equal(0, f.dependencies.length); + + c = d.dependencies[1]; + assert.ok(c.hasDependencies); + assert.equal('pub.c', c.extension.identifier); + assert.equal('pub.c', c.identifier); + assert.equal(d, c.dependent); + assert.equal(1, c.dependencies.length); + + d = c.dependencies[0]; + assert.ok(!d.hasDependencies); + assert.equal('pub.d', d.extension.identifier); + assert.equal('pub.d', d.identifier); + assert.equal(c, d.dependent); + assert.equal(0, d.dependencies.length); + + c = a.dependencies[1]; + d = c.dependencies[0]; + assert.ok(d.hasDependencies); + assert.equal('pub.d', d.extension.identifier); + assert.equal('pub.d', d.identifier); + assert.equal(c, d.dependent); + assert.equal(2, d.dependencies.length); + + f = d.dependencies[0]; + assert.ok(!f.hasDependencies); + assert.equal(null, f.extension); + assert.equal('pub.f', f.identifier); + assert.equal(d, f.dependent); + assert.equal(0, f.dependencies.length); + + c = d.dependencies[1]; + assert.ok(!c.hasDependencies); + assert.equal('pub.c', c.extension.identifier); + assert.equal('pub.c', c.identifier); + assert.equal(d, c.dependent); + assert.equal(0, c.dependencies.length); + + done(); + }); + }); + }); + + test('test disabled flags are false for uninstalled extension', (done) => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a'))); + testObject.queryGallery().done(pagedResponse => { + const actual = pagedResponse.firstPage[0]; + + assert.ok(!actual.disabledForWorkspace); + assert.ok(!actual.disabledGlobally); + done(); + }); + + }); + + test('test disabled flags are false for installed enabled extension', () => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + const actual = testObject.local[0]; + + assert.ok(!actual.disabledForWorkspace); + assert.ok(!actual.disabledGlobally); + }); + + test('test disabled for workspace is set', () => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.d', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.e', false, true); + + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + const actual = testObject.local[0]; + + assert.ok(actual.disabledForWorkspace); + assert.ok(!actual.disabledGlobally); + }); + + test('test disabled globally is set', () => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.d', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false, true); + + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + const actual = testObject.local[0]; + + assert.ok(!actual.disabledForWorkspace); + assert.ok(actual.disabledGlobally); + }); + + test('test disable flags are updated for user extensions', () => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + testObject.setEnablement(testObject.local[0], false, true); + const actual = testObject.local[0]; + + assert.ok(actual.disabledForWorkspace); + assert.ok(!actual.disabledGlobally); + }); + + test('test enable extension globally when extension is disabled for workspace', () => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false, true); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + testObject.setEnablement(testObject.local[0], true); + const actual = testObject.local[0]; + + assert.ok(!actual.disabledForWorkspace); + assert.ok(!actual.disabledGlobally); + }); + + test('test disable extension globally should not disable for workspace', () => { + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + testObject.setEnablement(testObject.local[0], false); + const actual = testObject.local[0]; + + assert.ok(!actual.disabledForWorkspace); + assert.ok(actual.disabledGlobally); + }); + + test('test disabled flags are not updated for system extensions', () => { + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a', {}, { type: LocalExtensionType.System })]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + testObject.setEnablement(testObject.local[0], false); + const actual = testObject.local[0]; + + assert.ok(!actual.disabledForWorkspace); + assert.ok(!actual.disabledGlobally); + }); + + test('test disabled flags are updated on change from outside', () => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + const actual = testObject.local[0]; + + assert.ok(!actual.disabledForWorkspace); + assert.ok(actual.disabledGlobally); + }); + + test('test change event is fired when disablement flags are changed', () => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + const target = sinon.spy(); + testObject.onChange(target); + + testObject.setEnablement(testObject.local[0], false); + + assert.ok(target.calledOnce); + }); + + test('test change event is fired when disablement flags are changed from outside', () => { + instantiationService.get(IExtensionEnablementService).setEnablement('pub.c', false); + instantiationService.get(IExtensionEnablementService).setEnablement('pub.b', false, true); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [aLocalExtension('a')]); + testObject = instantiationService.createInstance(ExtensionsWorkbenchService); + const target = sinon.spy(); + testObject.onChange(target); + + instantiationService.get(IExtensionEnablementService).setEnablement('pub.a', false); + + assert.ok(target.calledOnce); + }); + + function aLocalExtension(name: string = 'someext', manifest: any = {}, properties: any = {}): ILocalExtension { + const localExtension = Object.create({ manifest: {} }); + assign(localExtension, { type: LocalExtensionType.User, id: generateUuid() }, properties); + assign(localExtension.manifest, { name, publisher: 'pub' }, manifest); + localExtension.metadata = { id: localExtension.id, publisherId: localExtension.manifest.publisher, publisherDisplayName: 'somename' }; + return localExtension; + } + + function aGalleryExtension(name: string, properties: any = {}, galleryExtensionProperties: any = {}, assets: any = {}): IGalleryExtension { + const galleryExtension = Object.create({}); + assign(galleryExtension, { name, publisher: 'pub', id: generateUuid(), properties: {}, assets: {} }, properties); + assign(galleryExtension.properties, { dependencies: [] }, galleryExtensionProperties); + assign(galleryExtension.assets, assets); + return galleryExtension; + } + + function aPage(...objects: T[]): IPager { + return { firstPage: objects, total: objects.length, pageSize: objects.length, getPage: () => null }; + } + + function listenAfter(event: Event, count: number = 1): Event { + let counter = 0; + const emitter = new Emitter(); + event(() => { + if (++counter === count) { + emitter.fire(); + emitter.dispose(); + } + }); + return emitter.event; + } +}); \ No newline at end of file diff --git a/src/vs/workbench/parts/files/browser/editors/binaryFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/binaryFileEditor.ts index b451093c1ab..a8d93d2d011 100644 --- a/src/vs/workbench/parts/files/browser/editors/binaryFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/binaryFileEditor.ts @@ -8,7 +8,6 @@ import nls = require('vs/nls'); import { BaseBinaryResourceEditor } from 'vs/workbench/browser/parts/editor/binaryEditor'; import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/parts/files/common/files'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; /** * An implementation of editor for binary files like images. @@ -18,10 +17,9 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { public static ID = BINARY_FILE_EDITOR_ID; constructor( - @ITelemetryService telemetryService: ITelemetryService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService + @ITelemetryService telemetryService: ITelemetryService ) { - super(BinaryFileEditor.ID, telemetryService, editorService); + super(BinaryFileEditor.ID, telemetryService); } public getTitle(): string { diff --git a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts index b71b135b4af..63b71627209 100644 --- a/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts +++ b/src/vs/workbench/parts/files/browser/editors/textFileEditor.ts @@ -118,7 +118,7 @@ export class TextFileEditor extends BaseTextEditor { } // Different Input (Reload) - return this.editorService.resolveEditorModel(input, true /* Reload */).then(resolvedModel => { + return input.resolve(true).then(resolvedModel => { // There is a special case where the text editor has to handle binary file editor input: if a binary file // has been resolved and cached before, it maybe an actual instance of BinaryEditorModel. In this case our text diff --git a/src/vs/workbench/parts/files/browser/files.contribution.ts b/src/vs/workbench/parts/files/browser/files.contribution.ts index b750e467a74..62b37885cf0 100644 --- a/src/vs/workbench/parts/files/browser/files.contribution.ts +++ b/src/vs/workbench/parts/files/browser/files.contribution.ts @@ -195,7 +195,12 @@ configurationRegistry.registerConfiguration({ 'files.trimTrailingWhitespace': { 'type': 'boolean', 'default': false, - 'description': nls.localize('trimTrailingWhitespace', "When enabled, will trim trailing whitespace when you save a file.") + 'description': nls.localize('trimTrailingWhitespace', "When enabled, will trim trailing whitespace when saving a file.") + }, + 'files.insertFinalNewline': { + 'type': 'boolean', + 'default': false, + 'description': nls.localize('insertFinalNewline', "When enabled, insert a final new line at the end of the file when saving it.") }, 'files.autoSave': { 'type': 'string', diff --git a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts index 3222036b99e..50d18741538 100644 --- a/src/vs/workbench/parts/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/parts/files/browser/saveErrorHandler.ts @@ -12,7 +12,7 @@ import paths = require('vs/base/common/paths'); import { Action } from 'vs/base/common/actions'; import URI from 'vs/base/common/uri'; import product from 'vs/platform/product'; -import { EditorModel } from 'vs/workbench/common/editor'; +import { ITextEditorModel } from 'vs/workbench/common/editor'; import { EditorInputAction } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; @@ -29,6 +29,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; // A handler for save error happening with conflict resolution actions export class SaveErrorHandler implements ISaveErrorHandler, IWorkbenchContribution { @@ -179,15 +180,16 @@ export class FileOnDiskEditorInput extends ResourceEditorInput { fileResource: URI, name: string, description: string, - @IModelService modelService: IModelService, + @IModelService private modelService: IModelService, @IModeService private modeService: IModeService, + @ITextModelResolverService textModelResolverService: ITextModelResolverService, @IInstantiationService instantiationService: IInstantiationService, @ITextFileService private textFileService: ITextFileService ) { // We create a new resource URI here that is different from the file resource because we represent the state of // the file as it is on disk and not as it is (potentially cached) in Code. That allows us to have a different // model for the left-hand comparision compared to the conflicting one in Code to the right. - super(name, description, URI.from({ scheme: 'disk', path: fileResource.fsPath }), modelService, instantiationService); + super(name, description, URI.from({ scheme: 'disk', path: fileResource.fsPath }), textModelResolverService); this.fileResource = fileResource; } @@ -196,7 +198,7 @@ export class FileOnDiskEditorInput extends ResourceEditorInput { return this.lastModified; } - public resolve(refresh?: boolean): TPromise { + public resolve(refresh?: boolean): TPromise { // Make sure our file from disk is resolved up to date return this.textFileService.resolveTextContent(this.fileResource).then(content => { diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index 726b02bc31c..56a5d388455 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -8,11 +8,12 @@ import { TPromise } from 'vs/base/common/winjs.base'; import paths = require('vs/base/common/paths'); import labels = require('vs/base/common/labels'); import URI from 'vs/base/common/uri'; -import { EditorModel, EncodingMode, ConfirmResult } from 'vs/workbench/common/editor'; +import { EncodingMode, ConfirmResult } from 'vs/workbench/common/editor'; +import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; -import { IFileOperationResult, FileOperationResult, FileChangesEvent, EventType, FileChangeType } from 'vs/platform/files/common/files'; +import { IFileOperationResult, FileOperationResult } from 'vs/platform/files/common/files'; import { BINARY_FILE_EDITOR_ID, TEXT_FILE_EDITOR_ID, FILE_EDITOR_INPUT_ID, FileEditorInput as CommonFileEditorInput } from 'vs/workbench/parts/files/common/files'; -import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent, LocalFileChangeEvent } from 'vs/workbench/services/textfile/common/textfiles'; +import { ITextFileService, AutoSaveMode, ModelState, TextFileModelChangeEvent } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEventService } from 'vs/platform/event/common/event'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -64,23 +65,6 @@ export class FileEditorInput extends CommonFileEditorInput { this.toUnbind.push(this.textFileService.models.onModelSaveError(e => this.onDirtyStateChange(e))); this.toUnbind.push(this.textFileService.models.onModelSaved(e => this.onDirtyStateChange(e))); this.toUnbind.push(this.textFileService.models.onModelReverted(e => this.onDirtyStateChange(e))); - - // File changes - this.toUnbind.push(this.eventService.addListener2('files.internal:fileChanged', (e: LocalFileChangeEvent) => this.onLocalFileChange(e))); - this.toUnbind.push(this.eventService.addListener2(EventType.FILE_CHANGES, (e: FileChangesEvent) => this.onFileChanges(e))); - } - - private onLocalFileChange(e: LocalFileChangeEvent): void { - const movedTo = e.gotMoved() && e.getAfter() && e.getAfter().resource; - if (e.gotDeleted() || movedTo) { - this.disposeIfRelated(e.getBefore().resource, movedTo); - } - } - - private onFileChanges(e: FileChangesEvent): void { - if (e.gotDeleted()) { - this.disposeIfRelated(e); - } } private onDirtyStateChange(e: TextFileModelChangeEvent): void { @@ -194,7 +178,7 @@ export class FileEditorInput extends CommonFileEditorInput { return this.forceOpenAsBinary ? BINARY_FILE_EDITOR_ID : TEXT_FILE_EDITOR_ID; } - public resolve(refresh?: boolean): TPromise { + public resolve(refresh?: boolean): TPromise { return this.textFileService.models.loadOrCreate(this.resource, this.preferredEncoding, refresh).then(null, error => { // In case of an error that indicates that the file is binary or too large, just return with the binary editor model @@ -207,30 +191,6 @@ export class FileEditorInput extends CommonFileEditorInput { }); } - private disposeIfRelated(arg1: URI | FileChangesEvent, movedTo?: URI): void { - if (this.isDirty()) { - return; // we never dispose dirty files - } - - // Special case: a resource was renamed to the same path with different casing. Since our paths - // API is treating the paths as equal (they are on disk), we end up disposing the input we just - // renamed. The workaround is to detect that we do not dispose any input we are moving the file to - if (movedTo && movedTo.fsPath === this.resource.fsPath) { - return; - } - - let matches = false; - if (arg1 instanceof FileChangesEvent) { - matches = arg1.contains(this.resource, FileChangeType.DELETED); - } else { - matches = paths.isEqualOrParent(this.resource.toString(), arg1.toString()); - } - - if (matches) { - this.dispose(); - } - } - public dispose(): void { // Listeners diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts index 51402d85092..36c16325fa8 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorTracker.ts @@ -65,14 +65,84 @@ export class FileEditorTracker implements IWorkbenchContribution { // In any case there is no guarantee if the local event is fired first or the disk one. Thus, code must handle the case // that the event ordering is random as well as might not carry all information needed. private onLocalFileChange(e: LocalFileChangeEvent): void { + const movedTo = e.gotMoved() && e.getAfter() && e.getAfter().resource; // Handle moves specially when file is opened - if (e.gotMoved()) { + if (movedTo) { const before = e.getBefore(); const after = e.getAfter(); this.handleMovedFileInOpenedEditors(before ? before.resource : null, after ? after.resource : null); } + + // Handle deletes + if (e.gotDeleted() || movedTo) { + this.handleDeletes(e.getBefore().resource, movedTo); + } + } + + private onFileChanges(e: FileChangesEvent): void { + + // Handle updates to visible editors + this.handleUpdatesToVisibleEditors(e); + + // Handle deletes + if (e.gotDeleted()) { + this.handleDeletes(e); + } + } + + private handleDeletes(arg1: URI | FileChangesEvent, movedTo?: URI): void { + const fileInputs = this.getOpenedFileInputs(); + fileInputs.forEach(input => { + if (input.isDirty()) { + return; // we never dispose dirty files + } + + // Special case: a resource was renamed to the same path with different casing. Since our paths + // API is treating the paths as equal (they are on disk), we end up disposing the input we just + // renamed. The workaround is to detect that we do not dispose any input we are moving the file to + if (movedTo && movedTo.fsPath === input.getResource().fsPath) { + return; + } + + let matches = false; + if (arg1 instanceof FileChangesEvent) { + matches = arg1.contains(input.getResource(), FileChangeType.DELETED); + } else { + matches = paths.isEqualOrParent(input.getResource().toString(), arg1.toString()); + } + + if (matches) { + input.dispose(); + } + }); + } + + private getOpenedFileInputs(): FileEditorInput[] { + const inputs: FileEditorInput[] = []; + + const stacks = this.editorGroupService.getStacksModel(); + stacks.groups.forEach(group => { + group.getEditors().forEach(input => { + if (input instanceof FileEditorInput) { + inputs.push(input); + } else if (input instanceof DiffEditorInput) { + const originalInput = input.originalInput; + const modifiedInput = input.modifiedInput; + + if (originalInput instanceof FileEditorInput) { + inputs.push(originalInput); + } + + if (modifiedInput instanceof FileEditorInput) { + inputs.push(modifiedInput); + } + } + }); + }); + + return inputs; } private handleMovedFileInOpenedEditors(oldResource: URI, newResource: URI): void { @@ -100,12 +170,6 @@ export class FileEditorTracker implements IWorkbenchContribution { }); } - private onFileChanges(e: FileChangesEvent): void { - - // Handle updates to visible editors - this.handleUpdatesToVisibleEditors(e); - } - private handleUpdatesToVisibleEditors(e: FileChangesEvent) { const editors = this.editorService.getVisibleEditors(); editors.forEach(editor => { diff --git a/src/vs/workbench/parts/files/electron-browser/dirtyFilesTracker.ts b/src/vs/workbench/parts/files/electron-browser/dirtyFilesTracker.ts index 88443df9bde..8b17bef1205 100644 --- a/src/vs/workbench/parts/files/electron-browser/dirtyFilesTracker.ts +++ b/src/vs/workbench/parts/files/electron-browser/dirtyFilesTracker.ts @@ -11,8 +11,8 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { VIEWLET_ID } from 'vs/workbench/parts/files/common/files'; import { TextFileModelChangeEvent, ITextFileService, AutoSaveMode } from 'vs/workbench/services/textfile/common/textfiles'; import { platform, Platform } from 'vs/base/common/platform'; -import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; import { Position } from 'vs/platform/editor/common/editor'; +import { IWindowService } from 'vs/platform/windows/common/windows'; import { IEditorStacksModel } from 'vs/workbench/common/editor'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -23,8 +23,6 @@ import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/co import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import arrays = require('vs/base/common/arrays'); -import { ipcRenderer as ipc } from 'electron'; - export class DirtyFilesTracker implements IWorkbenchContribution { private isDocumentedEdited: boolean; private toUnbind: IDisposable[]; @@ -41,7 +39,7 @@ export class DirtyFilesTracker implements IWorkbenchContribution { @IEditorGroupService editorGroupService: IEditorGroupService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IActivityService private activityService: IActivityService, - @IWindowIPCService private windowService: IWindowIPCService, + @IWindowService private windowService: IWindowService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService ) { this.toUnbind = []; @@ -161,7 +159,7 @@ export class DirtyFilesTracker implements IWorkbenchContribution { const hasDirtyFiles = this.textFileService.isDirty(); this.isDocumentedEdited = hasDirtyFiles; - ipc.send('vscode:setDocumentEdited', this.windowService.getWindowId(), hasDirtyFiles); // handled from browser process + this.windowService.setDocumentEdited(hasDirtyFiles); } } diff --git a/src/vs/workbench/parts/files/electron-browser/electronFileActions.ts b/src/vs/workbench/parts/files/electron-browser/electronFileActions.ts index d973c906835..444981345a3 100644 --- a/src/vs/workbench/parts/files/electron-browser/electronFileActions.ts +++ b/src/vs/workbench/parts/files/electron-browser/electronFileActions.ts @@ -17,17 +17,15 @@ import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/edi import { asFileEditorInput } from 'vs/workbench/common/editor'; import { IMessageService } from 'vs/platform/message/common/message'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; -import { IWindowService } from 'vs/platform/windows/common/windows'; - -import { ipcRenderer as ipc, clipboard } from 'electron'; +import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; +import { clipboard } from 'electron'; export class RevealInOSAction extends Action { private resource: uri; constructor( resource: uri, - @IWindowIPCService private windowService: IWindowIPCService + @IWindowsService private windowsService: IWindowsService ) { super('workbench.action.files.revealInWindows', platform.isWindows ? nls.localize('revealInWindows', "Reveal in Explorer") : (platform.isMacintosh ? nls.localize('revealInMac', "Reveal in Finder") : nls.localize('openContainer', "Open Containing Folder"))); @@ -37,7 +35,7 @@ export class RevealInOSAction extends Action { } public run(): TPromise { - this.windowService.getWindow().showItemInFolder(paths.normalize(this.resource.fsPath, true)); + this.windowsService.showItemInFolder(paths.normalize(this.resource.fsPath, true)); return TPromise.as(true); } @@ -52,7 +50,7 @@ export class GlobalRevealInOSAction extends Action { id: string, label: string, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IWindowIPCService private windowService: IWindowIPCService, + @IWindowsService private windowsService: IWindowsService, @IMessageService private messageService: IMessageService ) { super(id, label); @@ -61,7 +59,7 @@ export class GlobalRevealInOSAction extends Action { public run(): TPromise { const fileInput = asFileEditorInput(this.editorService.getActiveEditorInput(), true); if (fileInput) { - this.windowService.getWindow().showItemInFolder(paths.normalize(fileInput.getResource().fsPath, true)); + this.windowsService.showItemInFolder(paths.normalize(fileInput.getResource().fsPath, true)); } else { this.messageService.show(severity.Info, nls.localize('openFileToReveal', "Open a file first to reveal")); } @@ -187,6 +185,7 @@ export class ShowOpenedFileInNewWindow extends Action { constructor( id: string, label: string, + @IWindowsService private windowsService: IWindowsService, @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IMessageService private messageService: IMessageService ) { @@ -196,7 +195,7 @@ export class ShowOpenedFileInNewWindow extends Action { public run(): TPromise { const fileInput = asFileEditorInput(this.editorService.getActiveEditorInput(), true); if (fileInput) { - ipc.send('vscode:windowOpen', [fileInput.getResource().fsPath], true /* force new window */); // handled from browser process + this.windowsService.windowOpen([fileInput.getResource().fsPath], true); } else { this.messageService.show(severity.Info, nls.localize('openFileToShow', "Open a file first to open in new window")); } diff --git a/src/vs/workbench/parts/files/electron-browser/files.electron.contribution.ts b/src/vs/workbench/parts/files/electron-browser/files.electron.contribution.ts index 334f527af2b..b08311c24cc 100644 --- a/src/vs/workbench/parts/files/electron-browser/files.electron.contribution.ts +++ b/src/vs/workbench/parts/files/electron-browser/files.electron.contribution.ts @@ -21,7 +21,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; class FileViewerActionContributor extends ActionBarContributor { @@ -85,4 +85,9 @@ actionsRegistry.registerActionBarContributor(Scope.VIEWER, FileViewerActionContr CommandsRegistry.registerCommand('_files.openFolderPicker', (accessor: ServicesAccessor, forceNewWindow: boolean) => { const windowService = accessor.get(IWindowService); windowService.openFolderPicker(forceNewWindow); +}); + +CommandsRegistry.registerCommand('_files.windowOpen', (accessor: ServicesAccessor, paths: string[], forceNewWindow: boolean) => { + const windowsService = accessor.get(IWindowsService); + windowsService.windowOpen(paths, forceNewWindow); }); \ No newline at end of file diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts index c78b564e61c..d3fded757d3 100644 --- a/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts +++ b/src/vs/workbench/parts/files/test/browser/fileEditorInput.test.ts @@ -6,31 +6,21 @@ import * as assert from 'assert'; import URI from 'vs/base/common/uri'; -import { join, basename } from 'vs/base/common/paths'; +import { join } from 'vs/base/common/paths'; import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { workbenchInstantiationService, TestTextFileService } from 'vs/test/utils/servicesTestUtils'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { EncodingMode } from 'vs/workbench/common/editor'; import { IEventService } from 'vs/platform/event/common/event'; -import { ITextFileEditorModel, ITextFileService, LocalFileChangeEvent } from 'vs/workbench/services/textfile/common/textfiles'; -import { FileOperationResult, IFileOperationResult, FileChangesEvent, FileChangeType, EventType } from 'vs/platform/files/common/files'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { FileOperationResult, IFileOperationResult } from 'vs/platform/files/common/files'; +import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; function toResource(path) { return URI.file(join('C:\\', new Buffer(this.test.fullTitle()).toString('base64'), path)); } -function toStat(resource: URI) { - return { - resource, - isDirectory: false, - hasChildren: false, - name: basename(resource.fsPath), - mtime: Date.now(), - etag: 'etag' - }; -} - class ServiceAccessor { constructor( @IWorkbenchEditorService public editorService: IWorkbenchEditorService, @@ -73,17 +63,17 @@ suite('Files - FileEditorInput', () => { const inputToResolve: any = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), void 0); const sameOtherInput = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/file.js'), void 0); - return accessor.editorService.resolveEditorModel(inputToResolve, true).then(resolved => { + return inputToResolve.resolve(true).then(resolved => { const resolvedModelA = resolved; - return accessor.editorService.resolveEditorModel(inputToResolve, true).then(resolved => { + return inputToResolve.resolve(true).then(resolved => { assert(resolvedModelA === resolved); // OK: Resolved Model cached globally per input - return accessor.editorService.resolveEditorModel(sameOtherInput, true).then(otherResolved => { + return sameOtherInput.resolve(true).then(otherResolved => { assert(otherResolved === resolvedModelA); // OK: Resolved Model cached globally per input inputToResolve.dispose(false); - return accessor.editorService.resolveEditorModel(inputToResolve, true).then(resolved => { + return inputToResolve.resolve(true).then(resolved => { assert(resolvedModelA === resolved); // Model is still the same because we had 2 clients inputToResolve.dispose(); @@ -91,15 +81,15 @@ suite('Files - FileEditorInput', () => { resolvedModelA.dispose(); - return accessor.editorService.resolveEditorModel(inputToResolve, true).then(resolved => { + return inputToResolve.resolve(true).then(resolved => { assert(resolvedModelA !== resolved); // Different instance, because input got disposed let stat = (resolved).versionOnDiskStat; - return accessor.editorService.resolveEditorModel(inputToResolve, true).then(resolved => { + return inputToResolve.resolve(true).then(resolved => { assert(stat !== (resolved).versionOnDiskStat); // Different stat, because resolve always goes to the server for refresh stat = (resolved).versionOnDiskStat; - return accessor.editorService.resolveEditorModel(inputToResolve, false).then(resolved => { + return inputToResolve.resolve(false).then(resolved => { assert(stat === (resolved).versionOnDiskStat); // Same stat, because not refreshed done(); @@ -127,7 +117,7 @@ suite('Files - FileEditorInput', () => { input.setEncoding('utf16', EncodingMode.Encode); assert.equal(input.getEncoding(), 'utf16'); - return accessor.editorService.resolveEditorModel(input, true).then((resolved: ITextFileEditorModel) => { + return input.resolve(true).then((resolved: TextFileEditorModel) => { assert.equal(input.getEncoding(), resolved.getEncoding()); resolved.dispose(); @@ -139,7 +129,7 @@ suite('Files - FileEditorInput', () => { test('save', function (done) { const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), void 0); - return accessor.editorService.resolveEditorModel(input, true).then((resolved: ITextFileEditorModel) => { + return input.resolve(true).then((resolved: TextFileEditorModel) => { resolved.textEditorModel.setValue('changed'); assert.ok(input.isDirty()); @@ -156,7 +146,7 @@ suite('Files - FileEditorInput', () => { test('revert', function (done) { const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), void 0); - return accessor.editorService.resolveEditorModel(input, true).then((resolved: ITextFileEditorModel) => { + return input.resolve(true).then((resolved: TextFileEditorModel) => { resolved.textEditorModel.setValue('changed'); assert.ok(input.isDirty()); @@ -178,7 +168,7 @@ suite('Files - FileEditorInput', () => { fileOperationResult: FileOperationResult.FILE_IS_BINARY }); - return accessor.editorService.resolveEditorModel(input, true).then(resolved => { + return input.resolve(true).then(resolved => { assert.ok(resolved); resolved.dispose(); @@ -186,51 +176,4 @@ suite('Files - FileEditorInput', () => { done(); }); }); - - test('disposes when resource gets deleted - local file changes', function () { - const parent = toResource.call(this, '/foo/bar'); - const resource = toResource.call(this, '/foo/bar/updatefile.js'); - let input = instantiationService.createInstance(FileEditorInput, resource, void 0); - - assert.ok(!input.isDisposed()); - - accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(resource))); - assert.ok(input.isDisposed()); - - input = instantiationService.createInstance(FileEditorInput, resource, void 0); - - const other = toResource.call(this, '/foo/barfoo'); - - accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(other))); - assert.ok(!input.isDisposed()); - - accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(parent))); - assert.ok(input.isDisposed()); - - // Move - const to = toResource.call(this, '/foo/barfoo/change.js'); - accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(resource), toStat(to))); - assert.ok(input.isDisposed()); - }); - - test('disposes when resource gets deleted - remote file changes', function () { - const parent = toResource.call(this, '/foo/bar'); - const resource = toResource.call(this, '/foo/bar/updatefile.js'); - let input = instantiationService.createInstance(FileEditorInput, resource, void 0); - - assert.ok(!input.isDisposed()); - - accessor.eventService.emit(EventType.FILE_CHANGES, new FileChangesEvent([{ resource, type: FileChangeType.DELETED }])); - assert.ok(input.isDisposed()); - - input = instantiationService.createInstance(FileEditorInput, resource, void 0); - - const other = toResource.call(this, '/foo/barfoo'); - - accessor.eventService.emit(EventType.FILE_CHANGES, new FileChangesEvent([{ resource: other, type: FileChangeType.DELETED }])); - assert.ok(!input.isDisposed()); - - accessor.eventService.emit(EventType.FILE_CHANGES, new FileChangesEvent([{ resource: parent, type: FileChangeType.DELETED }])); - assert.ok(input.isDisposed()); - }); }); \ No newline at end of file diff --git a/src/vs/workbench/parts/files/test/browser/fileEditorTracker.test.ts b/src/vs/workbench/parts/files/test/browser/fileEditorTracker.test.ts new file mode 100644 index 00000000000..050919514e5 --- /dev/null +++ b/src/vs/workbench/parts/files/test/browser/fileEditorTracker.test.ts @@ -0,0 +1,121 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import { FileEditorTracker } from 'vs/workbench/parts/files/common/editors/fileEditorTracker'; +import URI from 'vs/base/common/uri'; +import { join, basename } from 'vs/base/common/paths'; +import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { workbenchInstantiationService, TestTextFileService } from 'vs/test/utils/servicesTestUtils'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; +import { EditorStacksModel } from 'vs/workbench/common/editor/editorStacksModel'; +import { IEventService } from 'vs/platform/event/common/event'; +import { ITextFileService, LocalFileChangeEvent } from 'vs/workbench/services/textfile/common/textfiles'; +import { FileChangesEvent, FileChangeType, EventType } from 'vs/platform/files/common/files'; + +function toResource(path) { + return URI.file(join('C:\\', new Buffer(this.test.fullTitle()).toString('base64'), path)); +} + +function toStat(resource: URI) { + return { + resource, + isDirectory: false, + hasChildren: false, + name: basename(resource.fsPath), + mtime: Date.now(), + etag: 'etag' + }; +} + +class ServiceAccessor { + constructor( + @IWorkbenchEditorService public editorService: IWorkbenchEditorService, + @IEditorGroupService public editorGroupService: IEditorGroupService, + @ITextFileService public textFileService: TestTextFileService, + @IEventService public eventService: IEventService + ) { + } +} + +suite('Files - FileEditorTracker', () => { + + let instantiationService: IInstantiationService; + let accessor: ServiceAccessor; + + setup(() => { + instantiationService = workbenchInstantiationService(); + accessor = instantiationService.createInstance(ServiceAccessor); + }); + + test('disposes input when resource gets deleted - local file changes', function () { + const stacks = accessor.editorGroupService.getStacksModel() as EditorStacksModel; + const group = stacks.openGroup('first', true); + + const tracker = instantiationService.createInstance(FileEditorTracker); + assert.ok(tracker); + + const parent = toResource.call(this, '/foo/bar'); + const resource = toResource.call(this, '/foo/bar/updatefile.js'); + let input = instantiationService.createInstance(FileEditorInput, resource, void 0); + group.openEditor(input); + + assert.ok(!input.isDisposed()); + + accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(resource))); + assert.ok(input.isDisposed()); + group.closeEditor(input); + + input = instantiationService.createInstance(FileEditorInput, resource, void 0); + group.openEditor(input); + + const other = toResource.call(this, '/foo/barfoo'); + + accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(other))); + assert.ok(!input.isDisposed()); + + accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(parent))); + assert.ok(input.isDisposed()); + + // Move + const to = toResource.call(this, '/foo/barfoo/change.js'); + accessor.eventService.emit('files.internal:fileChanged', new LocalFileChangeEvent(toStat(resource), toStat(to))); + assert.ok(input.isDisposed()); + }); + + test('disposes when resource gets deleted - remote file changes', function () { + const stacks = accessor.editorGroupService.getStacksModel() as EditorStacksModel; + const group = stacks.openGroup('first', true); + + const tracker = instantiationService.createInstance(FileEditorTracker); + assert.ok(tracker); + + const parent = toResource.call(this, '/foo/bar'); + const resource = toResource.call(this, '/foo/bar/updatefile.js'); + let input = instantiationService.createInstance(FileEditorInput, resource, void 0); + group.openEditor(input); + + assert.ok(!input.isDisposed()); + + accessor.eventService.emit(EventType.FILE_CHANGES, new FileChangesEvent([{ resource, type: FileChangeType.DELETED }])); + assert.ok(input.isDisposed()); + group.closeEditor(input); + + input = instantiationService.createInstance(FileEditorInput, resource, void 0); + group.openEditor(input); + + const other = toResource.call(this, '/foo/barfoo'); + + accessor.eventService.emit(EventType.FILE_CHANGES, new FileChangesEvent([{ resource: other, type: FileChangeType.DELETED }])); + assert.ok(!input.isDisposed()); + + accessor.eventService.emit(EventType.FILE_CHANGES, new FileChangesEvent([{ resource: parent, type: FileChangeType.DELETED }])); + assert.ok(input.isDisposed()); + }); +}); \ No newline at end of file diff --git a/src/vs/workbench/parts/html/browser/html.contribution.ts b/src/vs/workbench/parts/html/browser/html.contribution.ts index 9bd1b592194..b4bc3c3113f 100644 --- a/src/vs/workbench/parts/html/browser/html.contribution.ts +++ b/src/vs/workbench/parts/html/browser/html.contribution.ts @@ -19,6 +19,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { isCommonCodeEditor, ICommonCodeEditor, IModel } from 'vs/editor/common/editorCommon'; import { HtmlZoneController } from './htmlEditorZone'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; // --- Register Editor (Registry.as(EditorExtensions.Editors)).registerEditor(new EditorDescriptor(HtmlPreviewPart.ID, @@ -59,7 +60,7 @@ CommandsRegistry.registerCommand('_workbench.htmlZone', function (accessor: Serv return; } - return accessor.get(IWorkbenchEditorService).resolveEditorModel({ resource: params.resource }).then(model => { + return accessor.get(ITextModelResolverService).resolve(params.resource).then(model => { const contents = (model.textEditorModel).getValue(); HtmlZoneController.getInstance(codeEditor).addZone(params.lineNumber, contents); }); diff --git a/src/vs/workbench/parts/html/browser/htmlPreviewPart.ts b/src/vs/workbench/parts/html/browser/htmlPreviewPart.ts index 545211aa7dd..ffea4d6a337 100644 --- a/src/vs/workbench/parts/html/browser/htmlPreviewPart.ts +++ b/src/vs/workbench/parts/html/browser/htmlPreviewPart.ts @@ -16,11 +16,11 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { Position } from 'vs/platform/editor/common/editor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel'; import { HtmlInput } from 'vs/workbench/parts/html/common/htmlInput'; import { IThemeService } from 'vs/workbench/services/themes/common/themeService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; import Webview from './webview'; /** @@ -30,7 +30,7 @@ export class HtmlPreviewPart extends BaseEditor { static ID: string = 'workbench.editor.htmlPreviewPart'; - private _editorService: IWorkbenchEditorService; + private _textModelResolverService: ITextModelResolverService; private _themeService: IThemeService; private _openerService: IOpenerService; private _webview: Webview; @@ -45,14 +45,14 @@ export class HtmlPreviewPart extends BaseEditor { constructor( @ITelemetryService telemetryService: ITelemetryService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, + @ITextModelResolverService textModelResolverService: ITextModelResolverService, @IThemeService themeService: IThemeService, @IOpenerService openerService: IOpenerService, @IWorkspaceContextService contextService: IWorkspaceContextService ) { super(HtmlPreviewPart.ID, telemetryService); - this._editorService = editorService; + this._textModelResolverService = textModelResolverService; this._themeService = themeService; this._openerService = openerService; this._baseUrl = contextService.toResource('/'); @@ -150,7 +150,7 @@ export class HtmlPreviewPart extends BaseEditor { return super.setInput(input, options).then(() => { let resourceUri = (input).getResource(); - return this._editorService.resolveEditorModel({ resource: resourceUri }).then(model => { + return this._textModelResolverService.resolve(resourceUri).then(model => { if (model instanceof BaseTextEditorModel) { this._model = model.textEditorModel; } diff --git a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts index 1a6f6d9ed24..3cc4ed721db 100644 --- a/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts +++ b/src/vs/workbench/parts/markers/browser/markersWorkbenchContributions.ts @@ -86,7 +86,7 @@ export function registerContributions(): void { }), 'View: ' + Messages.MARKERS_PANEL_TOGGLE_LABEL, Messages.MARKERS_PANEL_VIEW_CATEGORY); // Retaining old action to show errors and warnings, so that custom bindings to this action for existing users works. - registry.registerWorkbenchAction(new SyncActionDescriptor(markersPanelActions.ToggleErrorsAndWarningsAction, markersPanelActions.ToggleErrorsAndWarningsAction.ID, ''), Messages.SHOW_ERRORS_WARNINGS_ACTION_LABEL); + registry.registerWorkbenchAction(new SyncActionDescriptor(markersPanelActions.ToggleErrorsAndWarningsAction, markersPanelActions.ToggleErrorsAndWarningsAction.ID, Messages.SHOW_ERRORS_WARNINGS_ACTION_LABEL), ''); // Register StatusUpdater (platform.Registry.as(WorkbenchExtensions.Workbench)).registerWorkbenchContribution( diff --git a/src/vs/workbench/parts/markers/common/messages.ts b/src/vs/workbench/parts/markers/common/messages.ts index 6129f27dd88..f32eb9144b5 100644 --- a/src/vs/workbench/parts/markers/common/messages.ts +++ b/src/vs/workbench/parts/markers/common/messages.ts @@ -58,5 +58,5 @@ export default class Messages { } } - public static SHOW_ERRORS_WARNINGS_ACTION_LABEL: string = nls.localize('errors.warnings.show.label', "Errors and Warnings"); + public static SHOW_ERRORS_WARNINGS_ACTION_LABEL: string = nls.localize('errors.warnings.show.label', "Show Errors and Warnings"); } \ No newline at end of file diff --git a/src/vs/workbench/parts/search/browser/replaceService.ts b/src/vs/workbench/parts/search/browser/replaceService.ts index af14b817175..93ff400d0ab 100644 --- a/src/vs/workbench/parts/search/browser/replaceService.ts +++ b/src/vs/workbench/parts/search/browser/replaceService.ts @@ -21,13 +21,18 @@ import { IProgressRunner } from 'vs/platform/progress/common/progress'; import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; class EditorInputCache { private cache: Map.LinkedMap>; - constructor(private replaceService: ReplaceService, private editorService: IWorkbenchEditorService, - private modelService: IModelService) { + constructor( + private replaceService: ReplaceService, + private editorService: IWorkbenchEditorService, + private modelService: IModelService, + private textModelResolverService: ITextModelResolverService + ) { this.cache = new Map.LinkedMap>(); } @@ -52,7 +57,7 @@ class EditorInputCache { if (editorInputPromise) { editorInputPromise.done(() => { if (reloadFromSource) { - this.editorService.resolveEditorModel({ resource: fileMatch.resource() }).then(editorModel => { + this.textModelResolverService.resolve(fileMatch.resource()).then(editorModel => { if (editorModel.textEditorModel) { let replaceResource = this.getReplaceResource(fileMatch.resource()); this.modelService.getModel(replaceResource).setValue(editorModel.textEditorModel.getValue()); @@ -103,7 +108,7 @@ class EditorInputCache { private createRightInput(element: FileMatch): TPromise { return new TPromise((c, e, p) => { - this.editorService.resolveEditorModel({ resource: element.resource() }).then(value => { + this.textModelResolverService.resolve(element.resource()).then(value => { let model = value.textEditorModel; let replaceResource = this.getReplaceResource(element.resource()); this.modelService.createModel(model.getValue(), model.getMode(), replaceResource); @@ -128,8 +133,14 @@ export class ReplaceService implements IReplaceService { private cache: EditorInputCache; - constructor( @ITelemetryService private telemetryService: ITelemetryService, @IEventService private eventService: IEventService, @IEditorService private editorService, @IModelService private modelService: IModelService) { - this.cache = new EditorInputCache(this, editorService, modelService); + constructor( + @ITelemetryService private telemetryService: ITelemetryService, + @IEventService private eventService: IEventService, + @IEditorService private editorService: IWorkbenchEditorService, + @IModelService private modelService: IModelService, + @ITextModelResolverService private textModelResolverService: ITextModelResolverService + ) { + this.cache = new EditorInputCache(this, editorService, modelService, textModelResolverService); } public replace(match: Match): TPromise @@ -137,7 +148,7 @@ export class ReplaceService implements IReplaceService { public replace(match: FileMatchOrMatch, progress?: IProgressRunner, resource?: URI): TPromise public replace(arg: any, progress: IProgressRunner = null, resource: URI = null): TPromise { - let bulkEdit: BulkEdit = createBulkEdit(this.eventService, this.editorService, null); + let bulkEdit: BulkEdit = createBulkEdit(this.eventService, this.textModelResolverService, null); bulkEdit.progress(progress); if (arg instanceof Match) { diff --git a/src/vs/workbench/parts/search/browser/searchActions.ts b/src/vs/workbench/parts/search/browser/searchActions.ts index ccbbca22a6a..82c8bc71924 100644 --- a/src/vs/workbench/parts/search/browser/searchActions.ts +++ b/src/vs/workbench/parts/search/browser/searchActions.ts @@ -305,7 +305,7 @@ export abstract class AbstractSearchAndReplaceAction extends Action { private getNavigatorAt(element: FileMatchOrMatch, viewer: ITree): INavigator { let navigator: INavigator = viewer.getNavigator(); - while (navigator.current() !== element && !!navigator.next()) { }; + while (navigator.current() !== element && !!navigator.next()) { } return navigator; } } @@ -380,14 +380,15 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { } public run(): TPromise { + this.enabled = false; this.telemetryService.publicLog('replace.action.selected'); - let elementToFocus = this.getElementToFocusAfterRemoved(this.viewer, this.element); - let elementToShowReplacePreview = this.getElementToShowReplacePreview(elementToFocus); return this.element.parent().replace(this.element).then(() => { + let elementToFocus = this.getElementToFocusAfterReplace(); if (elementToFocus) { this.viewer.setFocus(elementToFocus); } + let elementToShowReplacePreview = this.getElementToShowReplacePreview(elementToFocus); this.viewer.DOMFocus(); if (!elementToShowReplacePreview || this.hasToOpenFile()) { this.viewlet.open(this.element, true); @@ -397,6 +398,33 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { }); } + private getElementToFocusAfterReplace(): Match { + let navigator: INavigator = this.viewer.getNavigator(); + let fileMatched = false; + let elementToFocus = null; + do { + elementToFocus = navigator.current(); + if (elementToFocus instanceof Match) { + if (elementToFocus.parent().id() === this.element.parent().id()) { + fileMatched = true; + if (this.element.range().getStartPosition().isBeforeOrEqual((elementToFocus).range().getStartPosition())) { + // Closest next match in the same file + break; + } + } else if (fileMatched) { + // First match in the next file (if expanded) + break; + } + } else if (fileMatched) { + if (!this.viewer.isExpanded(elementToFocus)) { + // Next file match (if collapsed) + break; + } + } + } while (!!navigator.next()); + return elementToFocus; + } + private getElementToShowReplacePreview(elementToFocus: FileMatchOrMatch): Match { if (this.hasSameParent(elementToFocus)) { return elementToFocus; diff --git a/src/vs/workbench/parts/search/common/searchModel.ts b/src/vs/workbench/parts/search/common/searchModel.ts index b1524004e32..2a9cc96160a 100644 --- a/src/vs/workbench/parts/search/common/searchModel.ts +++ b/src/vs/workbench/parts/search/common/searchModel.ts @@ -121,7 +121,7 @@ export class FileMatch extends Disposable { this._resource = this.rawMatch.resource; this._matches = new LinkedMap(); this._removedMatches = new ArraySet(); - this._updateScheduler = new RunOnceScheduler(this.updateMatches.bind(this), 250); + this._updateScheduler = new RunOnceScheduler(this.updateMatchesForModel.bind(this), 250); this.createMatches(); this.registerListeners(); @@ -131,7 +131,7 @@ export class FileMatch extends Disposable { let model = this.modelService.getModel(this._resource); if (model) { this.bindModel(model); - this.updateMatches(); + this.updateMatchesForModel(); } else { this.rawMatch.lineMatches.forEach((rawLineMatch) => { rawLineMatch.offsetAndLengths.forEach(offsetAndLength => { @@ -161,7 +161,7 @@ export class FileMatch extends Disposable { private onModelWillDispose(): void { // Update matches because model might have some dirty changes - this.updateMatches(); + this.updateMatchesForModel(); this.unbindModel(); } @@ -174,7 +174,7 @@ export class FileMatch extends Disposable { } } - private updateMatches(): void { + private updateMatchesForModel(): void { // this is called from a timeout and might fire // after the model has been disposed if (!this._model) { @@ -184,6 +184,24 @@ export class FileMatch extends Disposable { let matches = this._model .findMatches(this._query.pattern, this._model.getFullModelRange(), this._query.isRegExp, this._query.isCaseSensitive, this._query.isWordMatch); + this.updateMatches(matches); + } + + private updatesMatchesForLine(lineNumber: number): void { + const range = { + startLineNumber: lineNumber, + startColumn: this._model.getLineMinColumn(lineNumber), + endLineNumber: lineNumber, + endColumn: this._model.getLineMaxColumn(lineNumber) + }; + const oldMatches = this._matches.values().filter(match => match.range().startLineNumber === lineNumber); + oldMatches.forEach(match => this._matches.delete(match.id())); + + const matches = this._model.findMatches(this._query.pattern, range, this._query.isRegExp, this._query.isCaseSensitive, this._query.isWordMatch); + this.updateMatches(matches); + } + + private updateMatches(matches: Range[]) { matches.forEach(range => { let match = new Match(this, this._model.getLineContent(range.startLineNumber), range.startLineNumber - 1, range.startColumn - 1, range.endColumn - range.startColumn); if (!this._removedMatches.contains(match.id())) { @@ -231,11 +249,9 @@ export class FileMatch extends Disposable { this._onChange.fire(false); } - public replace(match: Match): TPromise { - return this.replaceService.replace(match).then(() => { - this.removeMatch(match); - this._onChange.fire(false); - }); + public replace(toReplace: Match): TPromise { + return this.replaceService.replace(toReplace) + .then(() => this.updatesMatchesForLine(toReplace.range().startLineNumber)); } public setSelectedMatch(match: Match) { diff --git a/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts b/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts index 7d1d3cedd35..1aa08b96c35 100644 --- a/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts +++ b/src/vs/workbench/parts/snippets/electron-browser/snippets.contribution.ts @@ -19,8 +19,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import * as JSONContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IModeService } from 'vs/editor/common/services/modeService'; - -import { ipcRenderer as ipc } from 'electron'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; import fs = require('fs'); class OpenSnippetsAction extends actions.Action { @@ -33,13 +32,14 @@ class OpenSnippetsAction extends actions.Action { label: string, @IEnvironmentService private environmentService: IEnvironmentService, @IQuickOpenService private quickOpenService: IQuickOpenService, - @IModeService private modeService: IModeService + @IModeService private modeService: IModeService, + @IWindowsService private windowsService: IWindowsService ) { super(id, label); } - private openFile(filePath: string): void { - ipc.send('vscode:windowOpen', [filePath]); // handled from browser process + private openFile(filePath: string): winjs.TPromise { + return this.windowsService.windowOpen([filePath]); } public run(): winjs.Promise { @@ -60,8 +60,7 @@ class OpenSnippetsAction extends actions.Action { var snippetPath = paths.join(this.environmentService.appSettingsHome, 'snippets', language.id + '.json'); return fileExists(snippetPath).then((success) => { if (success) { - this.openFile(snippetPath); - return winjs.TPromise.as(null); + return this.openFile(snippetPath); } var defaultContent = [ '{', @@ -82,7 +81,7 @@ class OpenSnippetsAction extends actions.Action { '}' ].join('\n'); return createFile(snippetPath, defaultContent).then(() => { - this.openFile(snippetPath); + return this.openFile(snippetPath); }, (err) => { errors.onUnexpectedError(nls.localize('openSnippet.errorOnCreate', 'Unable to create {0}', snippetPath)); }); diff --git a/src/vs/workbench/parts/terminal/test/terminalConfigHelper.test.ts b/src/vs/workbench/parts/terminal/test/terminalConfigHelper.test.ts index c1f62905490..c750606a570 100644 --- a/src/vs/workbench/parts/terminal/test/terminalConfigHelper.test.ts +++ b/src/vs/workbench/parts/terminal/test/terminalConfigHelper.test.ts @@ -20,6 +20,7 @@ class MockConfigurationService implements IConfigurationService { public reloadConfiguration(section?: string): TPromise { return TPromise.as(this.getConfiguration()); } public lookup(key: string) { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key) }; } public getConfiguration(): any { return this.configuration; } + public keys() { return { default: [], user: [] }; } public onDidUpdateConfiguration() { return { dispose() { } }; } } diff --git a/src/vs/workbench/parts/watermark/browser/watermark.ts b/src/vs/workbench/parts/watermark/browser/watermark.ts index 0d257995873..8a33c252f26 100644 --- a/src/vs/workbench/parts/watermark/browser/watermark.ts +++ b/src/vs/workbench/parts/watermark/browser/watermark.ts @@ -7,24 +7,46 @@ import 'vs/css!./watermark'; import { $ } from 'vs/base/browser/builder'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { isMacintosh } from 'vs/base/common/platform'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import * as nls from 'vs/nls'; import { Parts, IPartService } from 'vs/workbench/services/part/common/partService'; import { Registry } from 'vs/platform/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -const entries = [ +interface WatermarkEntry { + text: string; + ids: string[]; + folder?: boolean; +} + +const entries: WatermarkEntry[] = [ { - text: nls.localize('watermark.showCommands', "Command Palette"), + text: nls.localize('watermark.showCommands', "Show All Commands"), ids: ['workbench.action.showCommands'] }, { text: nls.localize('watermark.quickOpen', "Go to File"), - ids: ['workbench.action.quickOpen'] + ids: ['workbench.action.quickOpen'], + folder: true }, + isMacintosh ? + { + text: nls.localize('watermark.openFileFolder', "Open File or Folder"), + ids: ['workbench.action.files.openFileFolder'], + folder: false + } + : + { + text: nls.localize('watermark.openFile', "Open File"), + ids: ['workbench.action.files.openFile'], + folder: false + } + , { text: nls.localize('watermark.moveLines', "Move Lines Up/Down"), ids: ['editor.action.moveLinesUpAction', 'editor.action.moveLinesDownAction'] @@ -49,6 +71,7 @@ export class WatermarkContribution implements IWorkbenchContribution { @ILifecycleService lifecycleService: ILifecycleService, @IPartService private partService: IPartService, @IKeybindingService private keybindingService: IKeybindingService, + @IWorkspaceContextService private contextService: IWorkspaceContextService, @ITelemetryService telemetryService: ITelemetryService ) { if (telemetryService.getExperiments().showCommandsWatermark) { @@ -70,10 +93,12 @@ export class WatermarkContribution implements IWorkbenchContribution { .div({ 'class': 'watermark' }); const box = $(watermark) .div({ 'class': 'watermark-box' }); + const folder = !!this.contextService.getWorkspace(); + const selected = entries.filter(entry => !('folder' in entry) || entry.folder === folder); const update = () => { const builder = $(box); builder.clearChildren(); - entries.map(entry => { + selected.map(entry => { builder.element('dl', {}, dl => { dl.element('dt', {}, dt => dt.text(entry.text)); dl.element('dd', {}, dd => dd.innerHtml( diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index 0e922973077..ed2ae1d8d55 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IConfigurationService, IConfigurationValue } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationService, IConfigurationValue, IConfigurationKeys } from 'vs/platform/configuration/common/configuration'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; export const CONFIG_DEFAULT_NAME = 'settings'; @@ -23,14 +23,61 @@ export interface IWorkspaceConfigurationService extends IConfigurationService { * Override for the IConfigurationService#lookup() method that adds information about workspace settings. */ lookup(key: string): IWorkspaceConfigurationValue; + + /** + * Override for the IConfigurationService#keys() method that adds information about workspace settings. + */ + keys(): IWorkspaceConfigurationKeys; } export interface IWorkspaceConfigurationValue extends IConfigurationValue { workspace: T; } +export interface IWorkspaceConfigurationKeys extends IConfigurationKeys { + workspace: string[]; +} + export const WORKSPACE_STANDALONE_CONFIGURATIONS = { 'tasks': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/tasks.json`, 'launch': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/launch.json`, 'extensions': `${WORKSPACE_CONFIG_FOLDER_DEFAULT_NAME}/extensions.json` -}; \ No newline at end of file +}; + +export interface WorkspaceConfigurationNode { + [part: string]: IWorkspaceConfigurationValue | WorkspaceConfigurationNode; +} + +export function getWorkspaceConfigurationTree(configurationService: IWorkspaceConfigurationService): WorkspaceConfigurationNode { + const result: WorkspaceConfigurationNode = Object.create(null); + const keyset = configurationService.keys(); + const keys = [...keyset.workspace, ...keyset.user, ...keyset.default].sort(); + let lastKey: string; + for (const key of keys) { + if (key !== lastKey) { + lastKey = key; + const config = configurationService.lookup(key); + insert(result, key, config); + } + } + return result; +} + +function insert(root: WorkspaceConfigurationNode, key: string, value: any): void { + const parts = key.split('.'); + let i = 0; + while (i < parts.length - 1) { + let child = root[parts[i]]; + if (child) { + root = child; + i += 1; + } else { + break; + } + } + while (i < parts.length - 1) { + root = root[parts[i]] = Object.create(null); + i += 1; + } + root[parts[parts.length - 1]] = value; +} diff --git a/src/vs/workbench/services/configuration/common/model.ts b/src/vs/workbench/services/configuration/common/model.ts index 0d16e272ae5..c615c03ea5d 100644 --- a/src/vs/workbench/services/configuration/common/model.ts +++ b/src/vs/workbench/services/configuration/common/model.ts @@ -12,6 +12,7 @@ import { CONFIG_DEFAULT_NAME, WORKSPACE_CONFIG_DEFAULT_PATH } from 'vs/workbench export interface IConfigFile { contents: any; + raw?: any; parseError?: any; } @@ -24,7 +25,8 @@ export function newConfigFile(value: string): IConfigFile { } return { - contents: root + contents: root, + raw: contents }; } catch (e) { return { diff --git a/src/vs/workbench/services/configuration/node/configurationEditingService.ts b/src/vs/workbench/services/configuration/node/configurationEditingService.ts index b971f7c50fe..f61be27036d 100644 --- a/src/vs/workbench/services/configuration/node/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/node/configurationEditingService.ts @@ -11,7 +11,6 @@ import URI from 'vs/base/common/uri'; import * as json from 'vs/base/common/json'; import * as encoding from 'vs/base/node/encoding'; import strings = require('vs/base/common/strings'); -import { getConfigurationKeys } from 'vs/platform/configuration/common/model'; import { setProperty } from 'vs/base/common/jsonEdit'; import { Queue } from 'vs/base/common/async'; import { applyEdits } from 'vs/base/common/jsonFormatter'; @@ -145,7 +144,7 @@ export class ConfigurationEditingService implements IConfigurationEditingService // Any key must be a known setting from the registry (unless this is a standalone config) if (!operation.isWorkspaceStandalone) { - const validKeys = getConfigurationKeys(); + const validKeys = this.configurationService.keys().default; if (validKeys.indexOf(operation.key) < 0) { return TPromise.as({ error: ConfigurationEditingErrorCode.ERROR_UNKNOWN_KEY }); } diff --git a/src/vs/workbench/services/configuration/node/configurationService.ts b/src/vs/workbench/services/configuration/node/configurationService.ts index 6f88c4cf56e..e00355a3e36 100644 --- a/src/vs/workbench/services/configuration/node/configurationService.ts +++ b/src/vs/workbench/services/configuration/node/configurationService.ts @@ -52,6 +52,7 @@ export class WorkspaceConfigurationService implements IWorkspaceConfigurationSer private cachedConfig: any; private cachedWorkspaceConfig: any; + private cachedWorkspaceKeys: string[]; private bulkFetchFromWorkspacePromise: TPromise; private workspaceFilePathToConfiguration: { [relativeWorkspacePath: string]: TPromise }; @@ -125,6 +126,16 @@ export class WorkspaceConfigurationService implements IWorkspaceConfigurationSer }; } + public keys() { + const keys = this.baseConfigurationService.keys(); + + return { + default: keys.default, + user: keys.user, + workspace: this.cachedWorkspaceKeys + }; + } + public reloadConfiguration(section?: string): TPromise { // Reset caches to ensure we are hitting the disk @@ -144,6 +155,22 @@ export class WorkspaceConfigurationService implements IWorkspaceConfigurationSer const workspaceConfig = consolidate(workspaceConfigFiles).contents; this.cachedWorkspaceConfig = workspaceConfig; + // Cache keys + const workspaceConfigKeys = []; + Object.keys(workspaceConfigFiles).forEach(path => { + if (path === WORKSPACE_CONFIG_DEFAULT_PATH) { + workspaceConfigKeys.push(...Object.keys(workspaceConfigFiles[path].raw)); + } else { + const workspaceConfigs = Object.keys(WORKSPACE_STANDALONE_CONFIGURATIONS); + workspaceConfigs.forEach(workspaceConfig => { + if (path === WORKSPACE_STANDALONE_CONFIGURATIONS[workspaceConfig]) { + workspaceConfigKeys.push(...Object.keys(workspaceConfigFiles[path].raw).map(key => `${workspaceConfig}.${key}`)); + } + }); + } + }); + this.cachedWorkspaceKeys = workspaceConfigKeys; + // Override base (global < user) with workspace locals (global < user < workspace) return objects.mixin( objects.clone(this.baseConfigurationService.getConfiguration()), // target: global/default values (do NOT modify) diff --git a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts index 153042e7ee2..c9ba803c86f 100644 --- a/src/vs/workbench/services/configuration/test/node/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/node/configurationService.test.ts @@ -293,4 +293,72 @@ suite('WorkspaceConfigurationService - Node', () => { }); }); }); + + test('keys', (done: () => void) => { + const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'workspaceLookup.service.testSetting': { + 'type': 'string', + 'default': 'isSet' + } + } + }); + + function contains(array: string[], key: string): boolean { + return array.indexOf(key) >= 0; + } + + createWorkspace((workspaceDir, globalSettingsFile, cleanUp) => { + return createService(workspaceDir, globalSettingsFile).then(service => { + let keys = service.keys(); + + assert.ok(!contains(keys.default, 'something.missing')); + assert.ok(!contains(keys.user, 'something.missing')); + assert.ok(!contains(keys.workspace, 'something.missing')); + + assert.ok(contains(keys.default, 'workspaceLookup.service.testSetting')); + assert.ok(!contains(keys.user, 'workspaceLookup.service.testSetting')); + assert.ok(!contains(keys.workspace, 'workspaceLookup.service.testSetting')); + + fs.writeFileSync(globalSettingsFile, '{ "workspaceLookup.service.testSetting": true }'); + + return service.reloadConfiguration().then(() => { + keys = service.keys(); + + assert.ok(contains(keys.default, 'workspaceLookup.service.testSetting')); + assert.ok(contains(keys.user, 'workspaceLookup.service.testSetting')); + assert.ok(!contains(keys.workspace, 'workspaceLookup.service.testSetting')); + + const settingsFile = path.join(workspaceDir, '.vscode', 'settings.json'); + fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.testSetting": 55 }'); + + return service.reloadConfiguration().then(() => { + keys = service.keys(); + + assert.ok(contains(keys.default, 'workspaceLookup.service.testSetting')); + assert.ok(contains(keys.user, 'workspaceLookup.service.testSetting')); + assert.ok(contains(keys.workspace, 'workspaceLookup.service.testSetting')); + + const settingsFile = path.join(workspaceDir, '.vscode', 'tasks.json'); + fs.writeFileSync(settingsFile, '{ "workspaceLookup.service.taskTestSetting": 55 }'); + + return service.reloadConfiguration().then(() => { + keys = service.keys(); + + assert.ok(!contains(keys.default, 'tasks.workspaceLookup.service.taskTestSetting')); + assert.ok(!contains(keys.user, 'tasks.workspaceLookup.service.taskTestSetting')); + assert.ok(contains(keys.workspace, 'tasks.workspaceLookup.service.taskTestSetting')); + + service.dispose(); + + cleanUp(done); + }); + }); + }); + }); + }); + }); }); \ No newline at end of file diff --git a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts index 37645a560b3..bbcf1bb2e5d 100644 --- a/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/node/configurationResolverService.test.ts @@ -335,6 +335,7 @@ class MockConfigurationService implements IConfigurationService { public constructor(private configuration: any = {}) { } public reloadConfiguration(section?: string): TPromise { return TPromise.as(this.getConfiguration()); } public lookup(key: string) { return { value: getConfigurationValue(this.getConfiguration(), key), default: getConfigurationValue(this.getConfiguration(), key), user: getConfigurationValue(this.getConfiguration(), key) }; } + public keys() { return { default: [], user: [] }; } public getConfiguration(): any { return this.configuration; } public onDidUpdateConfiguration() { return { dispose() { } }; } } diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 589ec7f00d0..06cf03b2ce7 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -19,7 +19,7 @@ import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorIn import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorInput, IEditorModel, IEditorOptions, ITextEditorOptions, Position, Direction, IEditor, IResourceInput, ITextEditorModel } from 'vs/platform/editor/common/editor'; +import { IEditorInput, IEditorOptions, ITextEditorOptions, Position, Direction, IEditor, IResourceInput } from 'vs/platform/editor/common/editor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { AsyncDescriptor0 } from 'vs/platform/instantiation/common/descriptors'; @@ -195,18 +195,6 @@ export class WorkbenchEditorService implements IWorkbenchEditorService { return this.editorPart.closeAllEditors(except); } - public resolveEditorModel(input: IEditorInput, refresh?: boolean): TPromise; - public resolveEditorModel(input: IResourceInput, refresh?: boolean): TPromise; - public resolveEditorModel(input: any, refresh?: boolean): TPromise { - return this.createInput(input).then(typedInput => { - if (typedInput instanceof EditorInput) { - return typedInput.resolve(!!refresh); - } - - return TPromise.as(null); - }); - } - public createInput(input: EditorInput): TPromise; public createInput(input: IResourceInput): TPromise; public createInput(input: any): TPromise { diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index b5e6f08de81..94e9e8bc3d5 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -7,8 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IEditorService, IEditor, IEditorInput, IEditorOptions, ITextEditorOptions, Position, Direction, IResourceInput, IEditorModel } from 'vs/platform/editor/common/editor'; -import { ITextEditorModel } from 'vs/workbench/common/editor'; +import { IEditorService, IEditor, IEditorInput, IEditorOptions, ITextEditorOptions, Position, Direction, IResourceInput } from 'vs/platform/editor/common/editor'; export const IWorkbenchEditorService = createDecorator('editorService'); @@ -86,18 +85,6 @@ export interface IWorkbenchEditorService extends IEditorService { */ closeAllEditors(except?: Position): TPromise; - /** - * Resolves an input to its model representation. The optional parameter refresh allows to specify - * if a cached model should be returned (false) or a new version (true). The default is returning a - * cached version. - */ - resolveEditorModel(input: IEditorInput, refresh?: boolean): TPromise; - - /** - * Specific overload to resolve a IResourceInput to an editor model with a text representation. - */ - resolveEditorModel(input: IResourceInput, refresh?: boolean): TPromise; - /** * Allows to resolve an untyped input to a workbench typed instanceof editor input */ diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 10cd09a9078..92ea108d201 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -32,6 +32,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IIntegrityService } from 'vs/platform/integrity/common/integrity'; +import { ITitleService } from 'vs/workbench/services/title/common/titleService'; /** * Stores the selection & view state of an editor and allows to compare it to other selection states. @@ -90,20 +91,21 @@ export abstract class BaseHistoryService { protected contextService: IWorkspaceContextService, private configurationService: IConfigurationService, private environmentService: IEnvironmentService, - integrityService: IIntegrityService + integrityService: IIntegrityService, + private titleService: ITitleService ) { this.toUnbind = []; this.activeEditorListeners = []; this.isPure = true; // Window Title - window.document.title = this.getWindowTitle(null); + this.titleService.updateTitle(this.getWindowTitle(null)); // Integrity integrityService.isPure().then(r => { if (!r.isPure) { this.isPure = false; - window.document.title = this.getWindowTitle(this.editorService.getActiveEditorInput()); + this.titleService.updateTitle(this.getWindowTitle(this.editorService.getActiveEditorInput())); } }); @@ -174,7 +176,7 @@ export abstract class BaseHistoryService { windowTitle = this.getWindowTitle(null); } - window.document.title = windowTitle; + this.titleService.updateTitle(windowTitle); } protected abstract handleEditorSelectionChangeEvent(editor?: IBaseEditor): void; @@ -289,9 +291,10 @@ export class HistoryService extends BaseHistoryService implements IHistoryServic @ILifecycleService private lifecycleService: ILifecycleService, @IEventService private eventService: IEventService, @IInstantiationService private instantiationService: IInstantiationService, - @IIntegrityService integrityService: IIntegrityService + @IIntegrityService integrityService: IIntegrityService, + @ITitleService titleService: ITitleService ) { - super(editorGroupService, editorService, contextService, configurationService, environmentService, integrityService); + super(editorGroupService, editorService, contextService, configurationService, environmentService, integrityService, titleService); this.index = -1; this.stack = []; diff --git a/src/vs/workbench/services/message/browser/messagelist/messageList.css b/src/vs/workbench/services/message/browser/messageList.css similarity index 99% rename from src/vs/workbench/services/message/browser/messagelist/messageList.css rename to src/vs/workbench/services/message/browser/messageList.css index 8ee742da741..6a675f91f00 100644 --- a/src/vs/workbench/services/message/browser/messagelist/messageList.css +++ b/src/vs/workbench/services/message/browser/messageList.css @@ -6,6 +6,7 @@ .global-message-list { font-size: 12px; position: absolute; + top: 0; z-index: 300; color: #eee; list-style-type: none; diff --git a/src/vs/workbench/services/message/browser/messagelist/messageList.ts b/src/vs/workbench/services/message/browser/messageList.ts similarity index 98% rename from src/vs/workbench/services/message/browser/messagelist/messageList.ts rename to src/vs/workbench/services/message/browser/messageList.ts index 75a6408d304..0245e20274a 100644 --- a/src/vs/workbench/services/message/browser/messagelist/messageList.ts +++ b/src/vs/workbench/services/message/browser/messageList.ts @@ -67,6 +67,8 @@ export class MessageList { private _onMessagesShowing: Emitter; private _onMessagesCleared: Emitter; + private initialTopPosition: number; + constructor(container: HTMLElement, usageLogger?: IUsageLogger, options: IMessageListOptions = { purgeInterval: MessageList.DEFAULT_MESSAGE_PURGER_INTERVAL, maxMessages: MessageList.DEFAULT_MAX_MESSAGES, maxMessageLength: MessageList.DEFAULT_MAX_MESSAGE_LENGTH }) { this.messages = []; this.messageListPurger = null; @@ -169,6 +171,7 @@ export class MessageList { // Lazily create, otherwise clear old if (!this.messageListContainer) { this.messageListContainer = $('.global-message-list').appendTo(container); + this.initialTopPosition = parseInt(this.messageListContainer.getComputedStyle().getPropertyValue('top'), 10) || 0; } else { $(this.messageListContainer).empty(); $(this.messageListContainer).removeClass('transition'); @@ -196,7 +199,7 @@ export class MessageList { if (animate) { setTimeout(() => { $(this.messageListContainer).addClass('transition'); - $(this.messageListContainer).style('top', '0'); + $(this.messageListContainer).style('top', `${this.initialTopPosition}px`); }, 50 /* Need this delay to reliably get the animation on some browsers */); } }); diff --git a/src/vs/workbench/services/message/browser/messageService.ts b/src/vs/workbench/services/message/browser/messageService.ts index cc321faff2d..24ba1ec6f71 100644 --- a/src/vs/workbench/services/message/browser/messageService.ts +++ b/src/vs/workbench/services/message/browser/messageService.ts @@ -7,7 +7,7 @@ import errors = require('vs/base/common/errors'); import { toErrorMessage } from 'vs/base/common/errorMessage'; import types = require('vs/base/common/types'); -import { MessageList, Severity as BaseSeverity } from 'vs/workbench/services/message/browser/messagelist/messageList'; +import { MessageList, Severity as BaseSeverity } from 'vs/workbench/services/message/browser/messageList'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IMessageService, IMessageWithAction, IConfirmation, Severity } from 'vs/platform/message/common/message'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; diff --git a/src/vs/workbench/services/part/common/partService.ts b/src/vs/workbench/services/part/common/partService.ts index 5093252fee6..745cd91b004 100644 --- a/src/vs/workbench/services/part/common/partService.ts +++ b/src/vs/workbench/services/part/common/partService.ts @@ -12,7 +12,8 @@ export enum Parts { SIDEBAR_PART, PANEL_PART, EDITOR_PART, - STATUSBAR_PART + STATUSBAR_PART, + TITLEBAR_PART } export enum Position { @@ -20,6 +21,11 @@ export enum Position { RIGHT } +export interface ILayoutOptions { + forceStyleRecompute?: boolean; + toggleMaximizedPanel?: boolean; +} + export const IPartService = createDecorator('partService'); export interface IPartService { @@ -28,7 +34,7 @@ export interface IPartService { /** * Asks the part service to layout all parts. */ - layout(): void; + layout(options?: ILayoutOptions): void; /** * Asks the part service to if all parts have been created. @@ -65,6 +71,11 @@ export interface IPartService { */ setActivityBarHidden(hidden: boolean): void; + /** + * Returns iff the titlebar part is currently hidden or not. + */ + isTitleBarHidden(): boolean; + /** * Checks if the statusbar is currently hidden or not */ diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index d8195b636e8..d660d9594e4 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -19,11 +19,9 @@ import { IFileService, IResolveContentOptions, IFilesConfiguration, IFileOperati import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; -import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel'; import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -53,7 +51,6 @@ export abstract class TextFileService implements ITextFileService { @IConfigurationService private configurationService: IConfigurationService, @ITelemetryService private telemetryService: ITelemetryService, @IEditorGroupService private editorGroupService: IEditorGroupService, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, @IFileService protected fileService: IFileService, @IUntitledEditorService private untitledEditorService: IUntitledEditorService, @IInstantiationService private instantiationService: IInstantiationService @@ -441,21 +438,27 @@ export abstract class TextFileService implements ITextFileService { } private doSaveTextFileAs(sourceModel: ITextFileEditorModel | UntitledEditorModel, resource: URI, target: URI): TPromise { + // create the target file empty if it does not exist already return this.fileService.resolveFile(target).then(stat => stat, () => null).then(stat => stat || this.fileService.createFile(target)).then(stat => { - // resolve a model for the file (which can be binary if the file is not a text file) - return this.editorService.resolveEditorModel({ resource: target }).then((targetModel: ITextFileEditorModel) => { - // binary model: delete the file and run the operation again - if (targetModel instanceof BinaryEditorModel) { - return this.fileService.del(target).then(() => this.doSaveTextFileAs(sourceModel, resource, target)); - } - // text model: take over encoding and model value from source model + // resolve a model for the file (which can be binary if the file is not a text file) + return this.models.loadOrCreate(target).then((targetModel: ITextFileEditorModel) => { + + // take over encoding and model value from source model targetModel.updatePreferredEncoding(sourceModel.getEncoding()); targetModel.textEditorModel.setValue(sourceModel.getValue()); // save model return targetModel.save(); + }, error => { + + // binary model: delete the file and run the operation again + if ((error).fileOperationResult === FileOperationResult.FILE_IS_BINARY || (error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE) { + return this.fileService.del(target).then(() => this.doSaveTextFileAs(sourceModel, resource, target)); + } + + return TPromise.wrapError(error); }); }); } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 605772ca838..1f4d3bd7af5 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -171,7 +171,7 @@ export class TextFileEditorModelManager implements ITextFileEditorModelManager { return this.mapResourceToModel[resource.toString()]; } - public loadOrCreate(resource: URI, encoding: string, refresh?: boolean): TPromise { + public loadOrCreate(resource: URI, encoding?: string, refresh?: boolean): TPromise { // Return early if model is currently being loaded const pendingLoad = this.mapResourceToPendingModelLoaders[resource.toString()]; diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 52389b16b68..76f7a93fab9 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -192,7 +192,7 @@ export interface ITextFileEditorModelManager { getAll(resource?: URI): ITextFileEditorModel[]; - loadOrCreate(resource: URI, preferredEncoding: string, refresh?: boolean): TPromise; + loadOrCreate(resource: URI, preferredEncoding?: string, refresh?: boolean): TPromise; } export interface IModelSaveOptions { diff --git a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts index 980c1bbd88a..e746c770d26 100644 --- a/src/vs/workbench/services/textfile/electron-browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/electron-browser/textFileService.ts @@ -21,7 +21,6 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -43,13 +42,12 @@ export class TextFileService extends AbstractTextFileService { @ITelemetryService telemetryService: ITelemetryService, @IConfigurationService configurationService: IConfigurationService, @IModeService private modeService: IModeService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IEditorGroupService editorGroupService: IEditorGroupService, @IWindowIPCService private windowService: IWindowIPCService, @IModelService private modelService: IModelService, @IEnvironmentService private environmentService: IEnvironmentService ) { - super(lifecycleService, contextService, configurationService, telemetryService, editorGroupService, editorService, fileService, untitledEditorService, instantiationService); + super(lifecycleService, contextService, configurationService, telemetryService, editorGroupService, fileService, untitledEditorService, instantiationService); } public resolveTextContent(resource: URI, options?: IResolveContentOptions): TPromise { diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts new file mode 100644 index 00000000000..ee023c0cffe --- /dev/null +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -0,0 +1,147 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { TPromise } from 'vs/base/common/winjs.base'; +import URI from 'vs/base/common/uri'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IModel } from 'vs/editor/common/editorCommon'; +import { ITextEditorModel } from 'vs/platform/editor/common/editor'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { sequence } from 'vs/base/common/async'; +import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import network = require('vs/base/common/network'); +import { ITextModelResolverService, ITextModelContentProvider } from 'vs/platform/textmodelResolver/common/resolver'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; +import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { EditorInput } from 'vs/workbench/common/editor'; + +export class TextModelResolverService implements ITextModelResolverService { + + public _serviceBrand: any; + + private loadingTextModels: { [uri: string]: TPromise } = Object.create(null); + private contentProviderRegistry: { [scheme: string]: ITextModelContentProvider[] } = Object.create(null); + + constructor( + @ITextFileService private textFileService: ITextFileService, + @IUntitledEditorService private untitledEditorService: IUntitledEditorService, + @IWorkbenchEditorService private editorService: IWorkbenchEditorService, + @IInstantiationService private instantiationService: IInstantiationService, + @IModelService private modelService: IModelService + ) { + } + + public resolve(resource: URI): TPromise { + + // File Schema: use text file service + if (resource.scheme === network.Schemas.file) { + return this.textFileService.models.loadOrCreate(resource); + } + + // Untitled Schema: go through cached input + if (resource.scheme === UntitledEditorInput.SCHEMA) { + return this.untitledEditorService.createOrGet(resource).resolve(); + } + + // In Memory: only works on the active editor + if (resource.scheme === network.Schemas.inMemory) { + return this.editorService.createInput({ resource }).then(input => { + if (input instanceof EditorInput) { + return input.resolve(); + } + + return null; + }); + } + + // Any other resource: use content provider registry + return this.resolveTextModelContent(this.modelService, resource).then(() => this.instantiationService.createInstance(ResourceEditorModel, resource)); + } + + public registerTextModelContentProvider(scheme: string, provider: ITextModelContentProvider): IDisposable { + let array = this.contentProviderRegistry[scheme]; + if (!array) { + array = [provider]; + this.contentProviderRegistry[scheme] = array; + } else { + array.unshift(provider); + } + + const registry = this.contentProviderRegistry; + return { + dispose() { + const array = registry[scheme]; + const idx = array.indexOf(provider); + if (idx >= 0) { + array.splice(idx, 1); + if (array.length === 0) { + delete registry[scheme]; + } + } + } + }; + } + + private resolveTextModelContent(modelService: IModelService, resource: URI): TPromise { + const model = modelService.getModel(resource); + if (model) { + return TPromise.as(model); + } + + let loadingTextModel = this.loadingTextModels[resource.toString()]; + if (!loadingTextModel) { + + // make sure we have a provider this scheme + // the resource uses + const contentProviders = this.contentProviderRegistry[resource.scheme]; + if (!contentProviders) { + return TPromise.wrapError(`No model with uri '${resource}' nor a resolver for the scheme '${resource.scheme}'.`); + } + + // load the model-content from the provider and cache + // the loading such that we don't create the same model + // twice + this.loadingTextModels[resource.toString()] = loadingTextModel = new TPromise((resolve, reject) => { + let result: IModel; + let lastError: any; + + sequence(contentProviders.map(provider => { + return () => { + if (!result) { + const contentPromise = provider.provideTextContent(resource); + if (!contentPromise) { + return TPromise.wrapError(`No resolver for the scheme '${resource.scheme}' found.`); + } + + return contentPromise.then(value => { + result = value; + }, err => { + lastError = err; + }); + } + }; + })).then(() => { + if (!result && lastError) { + reject(lastError); + } else { + resolve(result); + } + }, reject); + + }, function () { + // no cancellation when caching promises + }); + + // remove the cached promise 'cos the model is now known to the model service (see above) + loadingTextModel.then(() => delete this.loadingTextModels[resource.toString()], () => delete this.loadingTextModels[resource.toString()]); + } + + return loadingTextModel; + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts new file mode 100644 index 00000000000..8cf824d6098 --- /dev/null +++ b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts @@ -0,0 +1,112 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import { IModel } from 'vs/editor/common/editorCommon'; +import { TPromise } from 'vs/base/common/winjs.base'; +import URI from 'vs/base/common/uri'; +import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; +import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { workbenchInstantiationService, TestTextFileService, toResource } from 'vs/test/utils/servicesTestUtils'; +import { ITextModelResolverService } from 'vs/platform/textmodelResolver/common/resolver'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; + +class ServiceAccessor { + constructor( + @ITextModelResolverService public textModelResolverServie: ITextModelResolverService, + @IModelService public modelService: IModelService, + @IModeService public modeService: IModeService, + @ITextFileService public textFileService: TestTextFileService, + @IUntitledEditorService public untitledEditorService: IUntitledEditorService + ) { + } +} + +suite('Workbench - TextModelResolverService', () => { + + let instantiationService: IInstantiationService; + let accessor: ServiceAccessor; + let model: TextFileEditorModel; + + setup(() => { + instantiationService = workbenchInstantiationService(); + accessor = instantiationService.createInstance(ServiceAccessor); + }); + + teardown(() => { + if (model) { + model.dispose(); + model = void 0; + } + (accessor.textFileService.models).clear(); + (accessor.textFileService.models).dispose(); + accessor.untitledEditorService.revertAll(); + }); + + test('resolve resource', function (done) { + const dispose = accessor.textModelResolverServie.registerTextModelContentProvider('test', { + provideTextContent: function (resource: URI): TPromise { + if (resource.scheme === 'test') { + let modelContent = 'Hello Test'; + let mode = accessor.modeService.getOrCreateMode('json'); + return TPromise.as(accessor.modelService.createModel(modelContent, mode, resource)); + } + + return TPromise.as(null); + } + }); + + let resource = URI.from({ scheme: 'test', authority: null, path: 'thePath' }); + let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); + + input.resolve().then((model: ResourceEditorModel) => { + assert.ok(model); + assert.equal(model.getValue(), 'Hello Test'); + + dispose.dispose(); + done(); + }); + }); + + test('resolve file', function (done) { + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8'); + (accessor.textFileService.models).add(model.getResource(), model); + model.load().then(() => { + accessor.textModelResolverServie.resolve(model.getResource()).then(model => { + const editorModel = model.textEditorModel as IModel; + + assert.ok(editorModel); + assert.equal(editorModel.getValue(), 'Hello Html'); + + done(); + }); + }); + }); + + test('resolve untitled', function (done) { + const service = accessor.untitledEditorService; + const input = service.createOrGet(); + + input.resolve().then(() => { + accessor.textModelResolverServie.resolve(input.getResource()).then(model => { + const editorModel = model.textEditorModel as IModel; + + assert.ok(editorModel); + + input.dispose(); + + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/src/vs/workbench/services/themes/electron-browser/stylesContributions.ts b/src/vs/workbench/services/themes/electron-browser/stylesContributions.ts index 62bc02fb659..27832128a7a 100644 --- a/src/vs/workbench/services/themes/electron-browser/stylesContributions.ts +++ b/src/vs/workbench/services/themes/electron-browser/stylesContributions.ts @@ -368,7 +368,7 @@ class EditorWhiteSpaceStyleRules extends EditorStyleRules { let themeSelector = theme.getSelector(); if (theme.getGlobalSettings().invisibles) { let invisibles = new Color(theme.getGlobalSettings().invisibles); - cssRules.push(`.monaco-editor.${themeSelector} .token.whitespace { color: ${invisibles} !important; }`); + cssRules.push(`.monaco-editor.${themeSelector} .token.vs-whitespace { color: ${invisibles} !important; }`); } } } diff --git a/src/vs/workbench/services/title/common/titleService.ts b/src/vs/workbench/services/title/common/titleService.ts new file mode 100644 index 00000000000..50b1a570e23 --- /dev/null +++ b/src/vs/workbench/services/title/common/titleService.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; + +export const ITitleService = createDecorator('titleService'); + +export interface ITitleService { + _serviceBrand: any; + + /** + * Update the window title with the given value. + */ + updateTitle(title: string): void; +} \ No newline at end of file diff --git a/src/vs/workbench/test/browser/services.test.ts b/src/vs/workbench/test/browser/services.test.ts index 0f9593655e6..73b9e94ddd6 100644 --- a/src/vs/workbench/test/browser/services.test.ts +++ b/src/vs/workbench/test/browser/services.test.ts @@ -16,7 +16,6 @@ import { EditorInput, EditorOptions, TextEditorOptions } from 'vs/workbench/comm import { StringEditorInput } from 'vs/workbench/common/editor/stringEditorInput'; import { StringEditorModel } from 'vs/workbench/common/editor/stringEditorModel'; import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; import { workbenchInstantiationService } from 'vs/test/utils/servicesTestUtils'; import { Viewlet } from 'vs/workbench/browser/viewlet'; import { IPanel } from 'vs/workbench/common/panel'; @@ -313,22 +312,17 @@ suite('Workbench UI Services', () => { // Resolve Editor Model (Typed EditorInput) let input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'hello world', 'text/plain', false); - service.resolveEditorModel(input, true).then((model: StringEditorModel) => { + input.resolve(true).then((model: StringEditorModel) => { assert(model instanceof StringEditorModel); assert(model.isResolved()); - service.resolveEditorModel(input, false).then((otherModel) => { + input.resolve().then((otherModel) => { assert(model === otherModel); input.dispose(); }); }); - - // Resolve Editor Model (Untyped Input) - service.resolveEditorModel({ resource: toResource.call(this, '/index.html') }, true).then((model) => { - assert(model instanceof TextFileEditorModel); - }); }); test('DelegatingWorkbenchEditorService', function () { diff --git a/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts b/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts new file mode 100644 index 00000000000..70394bfb33a --- /dev/null +++ b/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts @@ -0,0 +1,47 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import URI from 'vs/base/common/uri'; +import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; +import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { workbenchInstantiationService } from 'vs/test/utils/servicesTestUtils'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IModeService } from 'vs/editor/common/services/modeService'; + +class ServiceAccessor { + constructor( + @IModelService public modelService: IModelService, + @IModeService public modeService: IModeService + ) { + } +} + +suite('Workbench - ResourceEditorInput', () => { + + let instantiationService: IInstantiationService; + let accessor: ServiceAccessor; + + setup(() => { + instantiationService = workbenchInstantiationService(); + accessor = instantiationService.createInstance(ServiceAccessor); + }); + + test('simple', function (done) { + let resource = URI.from({ scheme: 'inMemory', authority: null, path: 'thePath' }); + accessor.modelService.createModel('function test() {}', accessor.modeService.getOrCreateMode('text'), resource); + let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); + + input.resolve().then((model: ResourceEditorModel) => { + assert.ok(model); + assert.equal(model.getValue(), 'function test() {}'); + + done(); + }); + }); +}); \ No newline at end of file diff --git a/src/vs/workbench/test/common/editor/stringEditorInput.test.ts b/src/vs/workbench/test/common/editor/stringEditorInput.test.ts index 0b784fef1d3..089731c19fc 100644 --- a/src/vs/workbench/test/common/editor/stringEditorInput.test.ts +++ b/src/vs/workbench/test/common/editor/stringEditorInput.test.ts @@ -10,7 +10,6 @@ import { TestInstantiationService } from 'vs/test/utils/instantiationTestUtils'; import URI from 'vs/base/common/uri'; import { StringEditorInput } from 'vs/workbench/common/editor/stringEditorInput'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; -import { ResourceEditorModel } from 'vs/workbench/common/editor/resourceEditorModel'; import { createMockModelService, TestEditorService } from 'vs/test/utils/servicesTestUtils'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; @@ -51,22 +50,22 @@ suite('Workbench - StringEditorInput', () => { input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); input = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); - editorService.resolveEditorModel(input, true).then(resolved => { + input.resolve(true).then(resolved => { let resolvedModelA = resolved; - return editorService.resolveEditorModel(input, true).then(resolved => { + return input.resolve(true).then(resolved => { assert(resolvedModelA === resolved); // assert: Resolved Model cached per instance let otherInput = instantiationService.createInstance(StringEditorInput, 'name', 'description', 'value', 'mode', false); - return editorService.resolveEditorModel(otherInput, true).then(resolved => { + return otherInput.resolve(true).then(resolved => { assert(resolvedModelA !== resolved); // NOT assert: Different instance, different model input.dispose(); - return editorService.resolveEditorModel(input, true).then(resolved => { + return input.resolve(true).then(resolved => { assert(resolvedModelA !== resolved); // Different instance, because input got disposed let model = (resolved).textEditorModel; - return editorService.resolveEditorModel(input, true).then(againResolved => { + return input.resolve(true).then(againResolved => { assert(model === (againResolved).textEditorModel); // Models should not differ because string input is constant input.dispose(); @@ -109,17 +108,4 @@ suite('Workbench - StringEditorInput', () => { assert.strictEqual(promiseEditorInput.matches(promiseEditorInput2), true); assert.strictEqual(stringEditorInput.matches(stringEditorInput2), true); }); - - test('ResourceEditorInput', function (done) { - let resource = URI.from({ scheme: 'inMemory', authority: null, path: 'thePath' }); - modelService.createModel('function test() {}', modeService.getOrCreateMode('text'), resource); - let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); - - input.resolve().then((model: ResourceEditorModel) => { - assert.ok(model); - assert.equal(model.getValue(), 'function test() {}'); - - done(); - }); - }); }); \ No newline at end of file diff --git a/src/vs/workbench/test/node/api/extHostConfiguration.test.ts b/src/vs/workbench/test/node/api/extHostConfiguration.test.ts index 50839cabd00..39666dc89fe 100644 --- a/src/vs/workbench/test/node/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/node/api/extHostConfiguration.test.ts @@ -10,6 +10,7 @@ import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration import { MainThreadConfigurationShape } from 'vs/workbench/api/node/extHost.protocol'; import { TPromise } from 'vs/base/common/winjs.base'; import { ConfigurationTarget, ConfigurationEditingErrorCode, IConfigurationEditingError } from 'vs/workbench/services/configuration/common/configurationEditing'; +import { WorkspaceConfigurationNode, IWorkspaceConfigurationValue } from 'vs/workbench/services/configuration/common/configuration'; suite('ExtHostConfiguration', function () { @@ -21,17 +22,107 @@ suite('ExtHostConfiguration', function () { } }; - function createExtHostConfiguration(data: any = {}, shape?: MainThreadConfigurationShape) { + function createExtHostConfiguration(data: WorkspaceConfigurationNode = {}, shape?: MainThreadConfigurationShape) { if (!shape) { shape = new class extends MainThreadConfigurationShape { }; } return new ExtHostConfiguration(shape, data); } - test('udate / section to key', function () { + function createConfigurationValue(value: T): IWorkspaceConfigurationValue { + return { + value, + default: value, + user: undefined, + workspace: undefined + }; + } + + test('has/get', function () { + + const all = createExtHostConfiguration({ + farboo: { + config0: createConfigurationValue(true), + nested: { + config1: createConfigurationValue(42), + config2: createConfigurationValue('Das Pferd frisst kein Reis.'), + }, + config4: createConfigurationValue('') + } + }); + + const config = all.getConfiguration('farboo'); + + assert.ok(config.has('config0')); + assert.equal(config.get('config0'), true); + assert.equal(config.get('config4'), ''); + assert.equal(config['config0'], true); + assert.equal(config['config4'], ''); + assert.throws(() => config['config4'] = 'valuevalue'); + + assert.ok(config.has('nested.config1')); + assert.equal(config.get('nested.config1'), 42); + assert.ok(config.has('nested.config2')); + assert.equal(config.get('nested.config2'), 'Das Pferd frisst kein Reis.'); + + assert.ok(config.has('nested')); + assert.deepEqual(config.get('nested'), { config1: 42, config2: 'Das Pferd frisst kein Reis.' }); + }); + + test('getConfiguration vs get', function () { + + const all = createExtHostConfiguration({ + farboo: { + config0: createConfigurationValue(true), + config4: createConfigurationValue('38') + } + }); + + let config = all.getConfiguration('farboo.config0'); + assert.equal(config.get(''), undefined); + assert.equal(config.has(''), false); + + config = all.getConfiguration('farboo'); + assert.equal(config.get('config0'), true); + assert.equal(config.has('config0'), true); + }); + + test('getConfiguration vs get', function () { + + const all = createExtHostConfiguration({ + farboo: { + config0: createConfigurationValue(true), + config4: createConfigurationValue('38') + } + }); + + let config = all.getConfiguration('farboo.config0'); + assert.equal(config.get(''), undefined); + assert.equal(config.has(''), false); + + config = all.getConfiguration('farboo'); + assert.equal(config.get('config0'), true); + assert.equal(config.has('config0'), true); + }); + + test('name vs property', function () { + const all = createExtHostConfiguration({ + farboo: { + get: createConfigurationValue('get-prop') + } + }); + const config = all.getConfiguration('farboo'); + + assert.ok(config.has('get')); + assert.equal(config.get('get'), 'get-prop'); + assert.deepEqual(config['get'], config.get); + assert.throws(() => config['get'] = 'get-prop'); + }); + + test('udate/section to key', function () { const shape = new RecordingShape(); - const allConfig = createExtHostConfiguration({ foo: { bar: 1, far: 2 } }, shape); + const allConfig = createExtHostConfiguration({ foo: { bar: createConfigurationValue(1), far: createConfigurationValue(2) } }, shape); let config = allConfig.getConfiguration('foo'); config.update('bar', 42, true); @@ -47,7 +138,7 @@ suite('ExtHostConfiguration', function () { assert.equal(shape.lastArgs[1], 'foo.bar'); }); - test('update / error-state not OK', function () { + test('update/error-state not OK', function () { const shape = new class extends MainThreadConfigurationShape { $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): TPromise { diff --git a/src/vs/workbench/test/node/api/mainThreadSaveParticipant.test.ts b/src/vs/workbench/test/node/api/mainThreadSaveParticipant.test.ts new file mode 100644 index 00000000000..59092f586f8 --- /dev/null +++ b/src/vs/workbench/test/node/api/mainThreadSaveParticipant.test.ts @@ -0,0 +1,75 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { FinalNewLineParticipant } from 'vs/workbench/api/node/mainThreadSaveParticipant'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { workbenchInstantiationService, TestTextFileService, toResource } from 'vs/test/utils/servicesTestUtils'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; +import { IEventService } from 'vs/platform/event/common/event'; +import { ITextFileService, SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; +import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager'; + +class ServiceAccessor { + constructor( @IEventService public eventService: IEventService, @ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService) { + } +} + +suite('MainThreadSaveParticipant', function () { + + let instantiationService: IInstantiationService; + let accessor: ServiceAccessor; + + setup(() => { + instantiationService = workbenchInstantiationService(); + accessor = instantiationService.createInstance(ServiceAccessor); + }); + + teardown(() => { + (accessor.textFileService.models).clear(); + TextFileEditorModel.setSaveParticipant(null); // reset any set participant + }); + + test('insert final new line', function (done) { + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/final_new_line.txt'), 'utf8'); + + model.load().then(() => { + const configService = new TestConfigurationService(); + configService.setUserConfiguration('files', { 'insertFinalNewline': true }); + + const participant = new FinalNewLineParticipant(configService, undefined); + + // No new line for empty lines + let lineContent = ''; + model.textEditorModel.setValue(lineContent); + participant.participate(model, { reason: SaveReason.EXPLICIT }); + assert.equal(model.getValue(), lineContent); + + // No new line if last line already empty + lineContent = `Hello New Line${model.textEditorModel.getEOL()}`; + model.textEditorModel.setValue(lineContent); + participant.participate(model, { reason: SaveReason.EXPLICIT }); + assert.equal(model.getValue(), lineContent); + + // New empty line added (single line) + lineContent = 'Hello New Line'; + model.textEditorModel.setValue(lineContent); + participant.participate(model, { reason: SaveReason.EXPLICIT }); + assert.equal(model.getValue(), `${lineContent}${model.textEditorModel.getEOL()}`); + + // New empty line added (multi line) + lineContent = `Hello New Line${model.textEditorModel.getEOL()}Hello New Line${model.textEditorModel.getEOL()}Hello New Line`; + model.textEditorModel.setValue(lineContent); + participant.participate(model, { reason: SaveReason.EXPLICIT }); + assert.equal(model.getValue(), `${lineContent}${model.textEditorModel.getEOL()}`); + + done(); + }); + }); +}); \ No newline at end of file