Merge branch 'main' into feat/git-bash-shell-integration

This commit is contained in:
Chapman Pendery 2024-03-27 16:12:24 -07:00 committed by GitHub
commit a06bbd27d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
63 changed files with 506 additions and 328 deletions

View file

@ -154,8 +154,6 @@
"src/vs/editor/contrib/codeAction/test/browser/codeActionModel.test.ts",
"src/vs/editor/test/common/services/languageService.test.ts",
"src/vs/editor/test/node/classification/typescript.test.ts",
"src/vs/editor/test/node/diffing/defaultLinesDiffComputer.test.ts",
"src/vs/editor/test/node/diffing/fixtures.test.ts",
"src/vs/platform/configuration/test/common/configuration.test.ts",
"src/vs/platform/extensions/test/common/extensionValidator.test.ts",
"src/vs/platform/opener/test/common/opener.test.ts",

View file

@ -1,5 +1,5 @@
disturl "https://electronjs.org/headers"
target "28.2.6"
ms_build_id "27476517"
target "28.2.8"
ms_build_id "27744544"
runtime "electron"
build_from_source "true"

View file

@ -1,75 +1,75 @@
2cd042f38fd13cbb3ed0e7205c6c892cd5f04fd4992d18da363b8f0df9dda3eb *chromedriver-v28.2.6-darwin-arm64.zip
05bc772ecb5728cde1efed2308074ad53a4abfe7c541a82d6fef62d3350c6cf4 *chromedriver-v28.2.6-darwin-x64.zip
4c7ea31be89009fcedfe8e3619be61bec6056c8bb9ea93b4e6a5deec791f8c55 *chromedriver-v28.2.6-linux-arm64.zip
ae61e86c512dff5108f2240018c3b549b57e25f3f31e822effb7f1d5a53cd474 *chromedriver-v28.2.6-linux-armv7l.zip
d2eac837adf3691abfab267d5e5f2428450c3ca506d74e47382bd0ae73755a4a *chromedriver-v28.2.6-linux-x64.zip
326f6f4ce44e42bae98894eb3f3ef125fe887a1188ce98d8cc1e8b68862283fe *chromedriver-v28.2.6-mas-arm64.zip
4cb08690d4db116f115e5da2f2d9ed9ccb287a33a8c9cb7264dba1329117f979 *chromedriver-v28.2.6-mas-x64.zip
ce1124ac3e5b91efc78d95260e5ecb001b362f12f1c9d2abc71fc3e8140aefb1 *chromedriver-v28.2.6-win32-arm64.zip
1a36b630b828953873a102c118d7954409de7ae0e40bdcb325baca0915fde4ff *chromedriver-v28.2.6-win32-ia32.zip
7e138e53e1acada2047c9adda42ee3760397cda56f7c73f30b48f69c51fb136f *chromedriver-v28.2.6-win32-x64.zip
f8809dc99407cc14bdc6579a6205d391ecf285a6d9ef49a34d529371616cd032 *electron-api.json
3bd369be1ce7175a637eb5531317c49c13287152cae4e0cfb875acdceee92fe3 *electron-v28.2.6-darwin-arm64-dsym-snapshot.zip
0020309287b4eef7cc59b761a1d604af80cca6d195cfecea5b97b834ba808d2a *electron-v28.2.6-darwin-arm64-dsym.zip
b1aeb1b30a965cf439456beaa3e99228437f3f9f91ddbbfa27a1695143a8a892 *electron-v28.2.6-darwin-arm64-symbols.zip
432ef2d5767991347c9452961e392182baa761d0b8b23483c1117a8c75bf18e9 *electron-v28.2.6-darwin-arm64.zip
c4723e680bf78ebe7e4a151d0b68c8e698985c36007237e9c5ffbd3976451519 *electron-v28.2.6-darwin-x64-dsym-snapshot.zip
86845958cedf3af045f07fd287066678e0ff73a8caf29c8032e8def0d3277b23 *electron-v28.2.6-darwin-x64-dsym.zip
450f7324fb9b0baed557133af50c8772a4b3e33f1288a7e732f7cc8fbd9df30d *electron-v28.2.6-darwin-x64-symbols.zip
524d710d21d64b539e568946debb3659b8e8071ead56c4b1a598c7c76fc32089 *electron-v28.2.6-darwin-x64.zip
c6ecf165f51d7da20278324a7454cc5119e6e546527dc9f21e7d4701f062443d *electron-v28.2.6-linux-arm64-debug.zip
cb495ec65c3a5cb6639a2ff1110f588cc82df241982e5cbb91932990de723772 *electron-v28.2.6-linux-arm64-symbols.zip
cdc832c6e337a2241bec78b7130f21c6db01d90d0ef93cd3c934f220319fa696 *electron-v28.2.6-linux-arm64.zip
c6ecf165f51d7da20278324a7454cc5119e6e546527dc9f21e7d4701f062443d *electron-v28.2.6-linux-armv7l-debug.zip
9eb155513a0a6f6fa518c2c768e0cc483a3e35c7beb7b657211df7bcf33ad144 *electron-v28.2.6-linux-armv7l-symbols.zip
6e340b9468950d8d3b5a9bf7840622403346f043af3f25471beff32212d227ce *electron-v28.2.6-linux-armv7l.zip
51567b886d0510726e733d9ecb33f32f14c78ee8cdedfa56adae26c0ac59b890 *electron-v28.2.6-linux-x64-debug.zip
fd6e2bc61e6df6113a74503d60bdea23d6734ba75bc270fa87f2a99a472d2e22 *electron-v28.2.6-linux-x64-symbols.zip
a5ec62621ccd0cd4636dc290a0406abc706c2900b518b085bff2312a5ee1dc6f *electron-v28.2.6-linux-x64.zip
1fb074339d42ef399254199418849f0fd591ba6bb203ab0570be192d7225921a *electron-v28.2.6-mas-arm64-dsym-snapshot.zip
3a8228698d1a85103eb3958de0ba8d77f1129a4eca44227a46dc70eda3ce2abc *electron-v28.2.6-mas-arm64-dsym.zip
3668d2aa7d00679f93106b1feb1dab4f1284bf5c6a041aa47284693786b3ad08 *electron-v28.2.6-mas-arm64-symbols.zip
ba40b18e6964fa96a72a86984032b534b94596b5a29418d286fba090f6ec8076 *electron-v28.2.6-mas-arm64.zip
dc7d071fb39d89c65745f6a567011959c4cd32e60e95cb92d970bc0ca89da26f *electron-v28.2.6-mas-x64-dsym-snapshot.zip
812909c73e1ebcb121e7874ae2250ed55ce58e3ef651fcfac9bd92284b1f6d69 *electron-v28.2.6-mas-x64-dsym.zip
fd720ee5353c20ff1ff0dc1b8eeaa64f28f7860268d5f8528d468ced0375086b *electron-v28.2.6-mas-x64-symbols.zip
9ce774a52e32a7df11c6ca20ae766303a33f1fd9000c628238fe93426b73216e *electron-v28.2.6-mas-x64.zip
952360b9cc257c145de62111cf9f0569892b3dfde3d4f8246b4025d8931c0377 *electron-v28.2.6-win32-arm64-pdb.zip
095500f4db01a8448cf7263a9db053446d88c08e1f6abd9a84323b7c45bd5a25 *electron-v28.2.6-win32-arm64-symbols.zip
c9f31ae6408aa6936b5d683eda601773789185890375cd097e61e924d4fed77a *electron-v28.2.6-win32-arm64-toolchain-profile.zip
99b24366555381bdaf35e4b85956941c859afbbfc52b5cc66bbda7ace4bcdc26 *electron-v28.2.6-win32-arm64.zip
85f92b7d9f5689c92216c71b3e76a3e1181f3b74b1a30649c5870126d197c057 *electron-v28.2.6-win32-ia32-pdb.zip
276b143933a186e397820424fddc6d0488d3293828e76273d64a6d642b64b67d *electron-v28.2.6-win32-ia32-symbols.zip
c9f31ae6408aa6936b5d683eda601773789185890375cd097e61e924d4fed77a *electron-v28.2.6-win32-ia32-toolchain-profile.zip
8f4547b567c5e88b7b5c08381d9da21210cbf796cf4b8348f2f15c139d03dc3a *electron-v28.2.6-win32-ia32.zip
1e875caf77e8ba4f622743e015522b1bef6b73eacebbfb00b9f62cd1fd46a3d3 *electron-v28.2.6-win32-x64-pdb.zip
c57843add2a3106247c3e16b5a246bfb43a046a114826f222004d72c54ab6e0b *electron-v28.2.6-win32-x64-symbols.zip
c9f31ae6408aa6936b5d683eda601773789185890375cd097e61e924d4fed77a *electron-v28.2.6-win32-x64-toolchain-profile.zip
cc27e8af85c8cde97cc53204b612365f3b1c53215e19bb5b6f303ea9491b4953 *electron-v28.2.6-win32-x64.zip
be5b134abac3cb2f771246712a564080b2e63475fe9f09accc7acb6ade03af3f *electron.d.ts
767539ad20af8cda91da9bf35183ddaea7a09aa3ee8274d2677f407502f24295 *ffmpeg-v28.2.6-darwin-arm64.zip
af8422c1596adf13887cac74aa185d3c84787174af305a49e558664162c0bbed *ffmpeg-v28.2.6-darwin-x64.zip
8e108e533811febcc51f377ac8604d506663453e41c02dc818517e1ea9a4e8d5 *ffmpeg-v28.2.6-linux-arm64.zip
51ecd03435f56a2ced31b1c9dbf281955ba82a814ca0214a4292bdc711e5a45c *ffmpeg-v28.2.6-linux-armv7l.zip
acc9dc3765f68b7563045e2d0df11bbef6b41be0a1c34bbf9fa778f36eefb42f *ffmpeg-v28.2.6-linux-x64.zip
d478d239203f337f146ba2d6f5af6640a82a8591faac23017f8709e0fbb61d8a *ffmpeg-v28.2.6-mas-arm64.zip
77bb31ee80979dce6b1ee786ab39eba7dd56dbdf29101e7046ee8cea1938e350 *ffmpeg-v28.2.6-mas-x64.zip
fc406f7a4239d5c37d4dbc44907184213b7e07de9d39796cbef7eaa4ead92549 *ffmpeg-v28.2.6-win32-arm64.zip
abd92844333712e2a2a891b2679cbaf434daf7aa50c371bfccccd553d2394300 *ffmpeg-v28.2.6-win32-ia32.zip
c5ce83bdfeb037f315bea8c97bfae344ebbec255fd173a7a769fd276b2bdbf28 *ffmpeg-v28.2.6-win32-x64.zip
cc27058b50af2fe95070f52aa72e417f27f440cac2ae0471f31af061181272fd *hunspell_dictionaries.zip
b593c7f79c5fd49794dcf260ebd8e5b757313b467d3f671c5d2422f7ed3829f2 *libcxx-objects-v28.2.6-linux-arm64.zip
92a9f593ccb41c5507c0be01f1ec061d4090290e45c9b6aa003070b4b8fcb839 *libcxx-objects-v28.2.6-linux-armv7l.zip
fce1088e2bbc3bbcacae1741c2f7f2508ddf0e00f41450ff96d83df655ee431e *libcxx-objects-v28.2.6-linux-x64.zip
ee7ad0db6eb01ee72a70bc6ecf27428d1fd31ab52329fb75aa2b2a9702b1c1d7 *libcxx_headers.zip
1a2473c8e94c23a2c00a580c1ae379e2e74cae89ccf9dae977ceb9ba44658801 *libcxxabi_headers.zip
9365c442b6bbce858814028fed11a79a518e64d433d01821264afdf5492f9308 *mksnapshot-v28.2.6-darwin-arm64.zip
8410f72e3696691cb38ea31acfc6d501291df43bd20636059aaafbef9dc7757d *mksnapshot-v28.2.6-darwin-x64.zip
e081547def25c9af1f1ace4aa3ed0ee175bae7c401c92ee42988981d605cb8a7 *mksnapshot-v28.2.6-linux-arm64-x64.zip
c6b2d51a82fd10a04532f33385c78921dd85722a9fe3de107ab4809df08ae0e8 *mksnapshot-v28.2.6-linux-armv7l-x64.zip
dc80bc57f86e361e0769e1ed62b1d083c0dd1d160c6fcb2c10ae821a83ae6333 *mksnapshot-v28.2.6-linux-x64.zip
9ff56ed57c48df1e449c334bbe61874bd495d92978924565fdd2ec99e5be7a54 *mksnapshot-v28.2.6-mas-arm64.zip
fb04465058adad0e56f7c3dfa6d9d85b249554595925669e7454348e28490e02 *mksnapshot-v28.2.6-mas-x64.zip
681633334d9eaab61ab95c3718ba98e7bf339615b6189d51b0782b77f5e8eaea *mksnapshot-v28.2.6-win32-arm64-x64.zip
d3986690b413d43cc6a003f8e09fd07bf213eb5f006f3419e9615fcc09d4891d *mksnapshot-v28.2.6-win32-ia32.zip
b26942469d96148f7ec410996d9e4c34c3c013a441e568b05c87e36a3d9ae441 *mksnapshot-v28.2.6-win32-x64.zip
69b40637a88ad4c17877b3d665b39ad0e11928aa71b19ef45f5b76250d1c9786 *chromedriver-v28.2.8-darwin-arm64.zip
3a9ce6179228245f2c7878c4238e10d51c77dc20642922a226ccc235a20f5a29 *chromedriver-v28.2.8-darwin-x64.zip
7f6470ea5d86dbe68fcc3fccfefd3b7135ba3468ef54b0235bf57cedeabf433d *chromedriver-v28.2.8-linux-arm64.zip
4bfe709d58b237f5c5a7618b2abecf533dac9415d327e763ad6cf622218517cc *chromedriver-v28.2.8-linux-armv7l.zip
7558ee413f96f88b9b9ad5787dd433adcfaf56411fdf052826d39d204ebaba9d *chromedriver-v28.2.8-linux-x64.zip
9814583b075d969c32afb6e929b4bf7956b0223fded996c91341388b8f638dd6 *chromedriver-v28.2.8-mas-arm64.zip
82d11c6606db9aea355b1e410083c72bd1e39abb9e34a839c16b16b75364ea0d *chromedriver-v28.2.8-mas-x64.zip
4803a5335a40ba208136094f5adfde2c4272761d34e0e9e9f4febc2ef676c3ad *chromedriver-v28.2.8-win32-arm64.zip
7b079f47869f7e96a5829f6fb7eff032394f76218b39a2aaf73cc93ce8a68050 *chromedriver-v28.2.8-win32-ia32.zip
2aedd176d4f72b29cd1914364e813756d52f53558df32e3429996b820edc994d *chromedriver-v28.2.8-win32-x64.zip
ae1a521aa36053a3b60b318d7bc093ec7579af6aa8b02bffe1f9e70d6922b726 *electron-api.json
a916f0cc438258f42f43955157565e7eca14966266f3fb123c8c736bece97daa *electron-v28.2.8-darwin-arm64-dsym-snapshot.zip
3c31d0a105b0632f15aa8adc68f06dc8ca47b1fdf1e62d1436ac43af117a22fb *electron-v28.2.8-darwin-arm64-dsym.zip
dab03f1cd7b499552d503bcca2fc1c3f40a1d2c463655ca3ace20778f08e9b04 *electron-v28.2.8-darwin-arm64-symbols.zip
2965d8c8d64fb6c51f5a283a246de653bfae22fe4bf9adf6c04592afabf62f04 *electron-v28.2.8-darwin-arm64.zip
03511a34d94d27eb576ab20e3a432c082a32a298475c7a85a329e029dddc55e4 *electron-v28.2.8-darwin-x64-dsym-snapshot.zip
96089786bd2723786673561c9b6f9a154928de663f2411f10153e6c985703eef *electron-v28.2.8-darwin-x64-dsym.zip
872789c3c218ab8f98be83c7781e3e6ef0114bd39780d65eaae77e99dbbda1de *electron-v28.2.8-darwin-x64-symbols.zip
a7889addd37254f842798bdd3ca34752b75acf6d8dd456cdeb2d75590c0a9ceb *electron-v28.2.8-darwin-x64.zip
fb90b8c903407ae575f9c8f727376519c0b35ed6f01dec55b177285b5db864e3 *electron-v28.2.8-linux-arm64-debug.zip
591248f7c94a6d7c4a4d8b2fcf63c8e4347018a65e1f68ed90e5549a587062c8 *electron-v28.2.8-linux-arm64-symbols.zip
6183db1029cebd9e0fb0e4f2d24a80b0274c5265756e66cb9fa0a480b92c98ea *electron-v28.2.8-linux-arm64.zip
fb90b8c903407ae575f9c8f727376519c0b35ed6f01dec55b177285b5db864e3 *electron-v28.2.8-linux-armv7l-debug.zip
87c4c534cd1d447b9d4632585a0d79c9d31114bd39ca63df1f2384afae3aa6b7 *electron-v28.2.8-linux-armv7l-symbols.zip
2a772b65815a0d47a756eed52f76cd9f27a8c277d7998bfcfe93b84a346eb255 *electron-v28.2.8-linux-armv7l.zip
773aa1f0bbe2b79765bf498958565f63957f8ec2e42327978a143dcbbc7f1bea *electron-v28.2.8-linux-x64-debug.zip
f8cbc6f2b719cc2f623afcfde8cb1d42614708793621a7a97b328015366b9b8f *electron-v28.2.8-linux-x64-symbols.zip
e7d17ee311299dfef3d2916987a513c4c1b66ad2e417c15fa5d29699602bd6cb *electron-v28.2.8-linux-x64.zip
5f0179fd7bf3927381bde24c9fb372fe95328be0500918cd6ee7f9503fae1ef5 *electron-v28.2.8-mas-arm64-dsym-snapshot.zip
e9810019f1d7b1b5a93fd1aee8adda5a872ebfb170de6d55cdd55162b923432d *electron-v28.2.8-mas-arm64-dsym.zip
4781376244c7df89d119575e2788ad43fae4387d850ef672665688081b30997c *electron-v28.2.8-mas-arm64-symbols.zip
a3932199781970e0b2fdb805d6556287ca877b35ac19384da00474140e14c41f *electron-v28.2.8-mas-arm64.zip
326cde32079496e0d976c5b65e85e5ce208eea3d8d23cd92c9e25f0fa6b30f40 *electron-v28.2.8-mas-x64-dsym-snapshot.zip
59a2b3d28dba45ee3016f8ab49a71b0c55f99ef046476183bc36890c9d335a71 *electron-v28.2.8-mas-x64-dsym.zip
313ff88f568c39079a1b7a1011f77fa03890cb9bb53649a489643311303cc3b8 *electron-v28.2.8-mas-x64-symbols.zip
41ab9f3addea5066d7e0ace28ebaead7128a2073931473c847aa9133b7df9248 *electron-v28.2.8-mas-x64.zip
179de6dd4835216bcd3e8bb9eb4d4b54013df865f52dbf0d5214726fc31cba9a *electron-v28.2.8-win32-arm64-pdb.zip
8628dec571206001420c1d8655904883d5de7e772d51ab2101b002c22e0dd25c *electron-v28.2.8-win32-arm64-symbols.zip
c9f31ae6408aa6936b5d683eda601773789185890375cd097e61e924d4fed77a *electron-v28.2.8-win32-arm64-toolchain-profile.zip
bb2a2a466d14c32c06ff09c42b3d1413f19fdc8a49a445d07d289fa453c268d3 *electron-v28.2.8-win32-arm64.zip
1d1efc3a1d17072bc76a4a63c8236a896d46f6f3badacd50bc5824149196d56f *electron-v28.2.8-win32-ia32-pdb.zip
9ddb1520de421a7c636160d01432c9bf111e6ef4b9a3be41b185c702c72353ac *electron-v28.2.8-win32-ia32-symbols.zip
c9f31ae6408aa6936b5d683eda601773789185890375cd097e61e924d4fed77a *electron-v28.2.8-win32-ia32-toolchain-profile.zip
38e22f9b0a32e0fc26e81905214e244c0a5d5c19e13c8ca2329ac75b62881472 *electron-v28.2.8-win32-ia32.zip
8168296e0454377e0113a7d0f87535d3d0e0c1a8538e8079ee1aae9c7223bb02 *electron-v28.2.8-win32-x64-pdb.zip
a276e9e748fa7db970e7dcce6f4ae571d8615a44e5208c0fa3c03de08774a4aa *electron-v28.2.8-win32-x64-symbols.zip
c9f31ae6408aa6936b5d683eda601773789185890375cd097e61e924d4fed77a *electron-v28.2.8-win32-x64-toolchain-profile.zip
079cc98f7933992ac7154e21e160d4a4c6b3541c26b56fc6f8438e9eabc369b9 *electron-v28.2.8-win32-x64.zip
f838e4a7c24518c5fa25d4a23acf869737cfa88761019cea4f83ebfb302363ec *electron.d.ts
4450bcc66cece4ff2373563e0123799f95645fa155577a8f380211b29e8b4ec9 *ffmpeg-v28.2.8-darwin-arm64.zip
152e3ed53098d24f356d7ec640d19efc57f7f34c39d8b8278f2586985d4a99a1 *ffmpeg-v28.2.8-darwin-x64.zip
8e108e533811febcc51f377ac8604d506663453e41c02dc818517e1ea9a4e8d5 *ffmpeg-v28.2.8-linux-arm64.zip
51ecd03435f56a2ced31b1c9dbf281955ba82a814ca0214a4292bdc711e5a45c *ffmpeg-v28.2.8-linux-armv7l.zip
acc9dc3765f68b7563045e2d0df11bbef6b41be0a1c34bbf9fa778f36eefb42f *ffmpeg-v28.2.8-linux-x64.zip
15a2a4a28a66e65122eb4f2bd796ccd5b6ed45420a034878affd002fc8c290dc *ffmpeg-v28.2.8-mas-arm64.zip
2dfe2f524c5220f50c7b6fe08605a67631b5520e0c82842e1f41f677cac17643 *ffmpeg-v28.2.8-mas-x64.zip
313e2979f0df88715159c0737bfbb5ae1d5c79fb9820e94d2a93ba71d3324ecd *ffmpeg-v28.2.8-win32-arm64.zip
9e73bc07563aefa8b9625676939a410b35a823d961b96da0e8edd90d7e5fb47b *ffmpeg-v28.2.8-win32-ia32.zip
1b11042defc8a3f403e5567fa4a4b8c59b224f3b7b52d44d6c7197b96af7b53b *ffmpeg-v28.2.8-win32-x64.zip
1e2e9480d4228f6bbc731ff7ee413b9e97656c36b15418d20681a76d82902b86 *hunspell_dictionaries.zip
8c8b967cf4c78ed9bbf4921b2c616257f45b137412eb3bc64176066c3e47bbe8 *libcxx-objects-v28.2.8-linux-arm64.zip
56af259535ccfaac295b82ce68686f9582265cb2ebe2783852f518c0fabc8a1e *libcxx-objects-v28.2.8-linux-armv7l.zip
b590e001dc98e32e5952ca69573e6f1bcec5e2f2d99052d1089ab72084cccea1 *libcxx-objects-v28.2.8-linux-x64.zip
c0634d5c92f0a2983b17c866f7d3694cb75f6e78cd07b10d9488ef46acc66a50 *libcxx_headers.zip
99ee16441d9eb2b92a05d5a5c9b9dc4cdfab33cb09595e9d78fd2ba503dead5b *libcxxabi_headers.zip
a95de1da301d641caaafaea9869c4c7834c254f818ac0c10d97402b2220c8be3 *mksnapshot-v28.2.8-darwin-arm64.zip
e5ef6b35d7cd807f93babfedbbde513ab6053ad9fb80b0f7abc1bfda414daaa1 *mksnapshot-v28.2.8-darwin-x64.zip
eeb6c5b7962af8d5cfaa97b2cf96d312d0ad57a3abb3e00774d50ea2e005bb9b *mksnapshot-v28.2.8-linux-arm64-x64.zip
0adacd0767469f90400b1f17ba8ac3ccb33cfeb11a8ef54d70bc8adb7cc306dc *mksnapshot-v28.2.8-linux-armv7l-x64.zip
5242817f1f26e10804e7e2446d0a8a64e8b2958cdba01e79d89db883d9d960d0 *mksnapshot-v28.2.8-linux-x64.zip
0ecb67673508c10f4fe08e7cb80300b9a8f507f50994c79caf302ff78ef748ca *mksnapshot-v28.2.8-mas-arm64.zip
19429da56077f12de4d4563f49c55f4f1f0fe61f66863804640fc55e65ee98f9 *mksnapshot-v28.2.8-mas-x64.zip
c7b47ae63c2f6eb07b06379206e6f215fbcb2b9a49faa72ca850bf8f9b998c4c *mksnapshot-v28.2.8-win32-arm64-x64.zip
0032660a9f8575a153951f29adae49a18e400b40906eec803fe7e3d2e970503d *mksnapshot-v28.2.8-win32-ia32.zip
2c71c9a2bd4441e580dc3083073e712fba94e0236415c8ab35320da52f492508 *mksnapshot-v28.2.8-win32-x64.zip

View file

@ -528,12 +528,12 @@
"git": {
"name": "electron",
"repositoryUrl": "https://github.com/electron/electron",
"commitHash": "2977fc4025fbc4c02ae9e87e480a94062b2ca4da"
"commitHash": "31cd9d1f61714e20f1067d726404600ab7281698"
}
},
"isOnlyProductionDependency": true,
"license": "MIT",
"version": "28.2.6"
"version": "28.2.8"
},
{
"component": {

View file

@ -4,7 +4,7 @@
"license": "MIT",
"description": "Dependencies shared by all extensions",
"dependencies": {
"typescript": "5.4"
"typescript": "5.4.3"
},
"scripts": {
"postinstall": "node ./postinstall.mjs"

View file

@ -234,10 +234,10 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
typescript@5.4:
version "5.4.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372"
integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==
typescript@5.4.3:
version "5.4.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff"
integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==
vscode-grammar-updater@^1.1.0:
version "1.1.0"

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.88.0",
"distro": "0d4298753acb3d9ade428d16cda9ae86015707c2",
"distro": "340432a8308f66007779ec2133ee39e6995006cb",
"author": {
"name": "Microsoft Corporation"
},
@ -149,7 +149,7 @@
"cssnano": "^6.0.3",
"debounce": "^1.0.0",
"deemon": "^1.8.0",
"electron": "28.2.6",
"electron": "28.2.8",
"eslint": "8.36.0",
"eslint-plugin-header": "3.1.1",
"eslint-plugin-jsdoc": "^46.5.0",

View file

@ -39,17 +39,19 @@ export class Cache<T> {
/**
* Uses a LRU cache to make a given parametrized function cached.
* Caches just the last value.
* The key must be JSON serializable.
*/
export class LRUCachedFunction<TArg, TComputed> {
private lastCache: TComputed | undefined = undefined;
private lastArgKey: string | undefined = undefined;
private lastArgKey: unknown | undefined = undefined;
constructor(private readonly fn: (arg: TArg) => TComputed) {
constructor(
private readonly fn: (arg: TArg) => TComputed,
private readonly _computeKey: (arg: TArg) => unknown = JSON.stringify,
) {
}
public get(arg: TArg): TComputed {
const key = JSON.stringify(arg);
const key = this._computeKey(arg);
if (this.lastArgKey !== key) {
this.lastArgKey = key;
this.lastCache = this.fn(arg);

View file

@ -3,10 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IObservable, ISettableObservable, derived, observableValue } from 'vs/base/common/observable';
import { IObservable, ISettableObservable, derived, observableFromEvent, observableValue } from 'vs/base/common/observable';
import { Constants } from 'vs/base/common/uint';
import { diffEditorDefaultOptions } from 'vs/editor/common/config/diffEditor';
import { IDiffEditorBaseOptions, IDiffEditorOptions, IEditorOptions, ValidDiffEditorBaseOptions, clampedFloat, clampedInt, boolean as validateBooleanOption, stringSet as validateStringSetOption } from 'vs/editor/common/config/editorOptions';
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
export class DiffEditorOptions {
private readonly _options: ISettableObservable<IEditorOptions & Required<IDiffEditorBaseOptions>, { changedOptions: IDiffEditorOptions }>;
@ -15,8 +16,11 @@ export class DiffEditorOptions {
private readonly _diffEditorWidth = observableValue<number>(this, 0);
private readonly _screenReaderMode = observableFromEvent(this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized());
constructor(
options: Readonly<IDiffEditorOptions>,
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
) {
const optionsCopy = { ...options, ...validateDiffEditorOptions(options, diffEditorDefaultOptions) };
this._options = observableValue(this, optionsCopy);
@ -28,7 +32,7 @@ export class DiffEditorOptions {
public readonly renderOverviewRuler = derived(this, reader => this._options.read(reader).renderOverviewRuler);
public readonly renderSideBySide = derived(this, reader => this._options.read(reader).renderSideBySide
&& !(this._options.read(reader).useInlineViewWhenSpaceIsLimited && this.couldShowInlineViewBecauseOfSize.read(reader))
&& !(this._options.read(reader).useInlineViewWhenSpaceIsLimited && this.couldShowInlineViewBecauseOfSize.read(reader) && !this._screenReaderMode.read(reader))
);
public readonly readOnly = derived(this, reader => this._options.read(reader).readOnly);

View file

@ -117,7 +117,7 @@ export class DiffEditorWidget extends DelegatingEditor implements IDiffEditor {
this._rootSizeObserver = this._register(new ObservableElementSizeObserver(this.elements.root, options.dimension));
this._rootSizeObserver.setAutomaticLayout(options.automaticLayout ?? false);
this._options = new DiffEditorOptions(options);
this._options = this._instantiationService.createInstance(DiffEditorOptions, options);
this._register(autorun(reader => {
this._options.setWidth(this._rootSizeObserver.width.read(reader));
}));

View file

@ -118,10 +118,12 @@ export class EditorGutter<T extends IGutterItemInfo = IGutterItemInfo> extends D
gutterItem.range.startLineNumber <= this._editor.getModel()!.getLineCount()
? this._editor.getTopForLineNumber(gutterItem.range.startLineNumber, true) - scrollTop
: this._editor.getBottomForLineNumber(gutterItem.range.startLineNumber - 1, false) - scrollTop;
const bottom = this._editor.getBottomForLineNumber(gutterItem.range.endLineNumberExclusive - 1, true) - scrollTop;
const bottom = gutterItem.range.isEmpty
// Don't trust that `getBottomForLineNumber` for the previous line equals `getTopForLineNumber` for the current one.
? top
: (this._editor.getBottomForLineNumber(gutterItem.range.endLineNumberExclusive - 1, true) - scrollTop);
const height = bottom - top;
view.domNode.style.top = `${top}px`;
view.domNode.style.height = `${height}px`;

View file

@ -87,7 +87,7 @@ export class DocumentDiffItemViewModel extends Disposable {
};
}
const options = new DiffEditorOptions(updateOptions(this.entry.value!.options || {}));
const options = this._instantiationService.createInstance(DiffEditorOptions, updateOptions(this.entry.value!.options || {}));
if (this.entry.value!.onOptionsDidChange) {
this._register(this.entry.value!.onOptionsDidChange(() => {
options.updateOptions(updateOptions(this.entry.value!.options || {}));

View file

@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { derived, derivedWithStore, observableValue, recomputeInitiallyAndOnChange } from 'vs/base/common/observable';
import { readHotReloadableExport } from 'vs/editor/browser/widget/diffEditor/utils';
import { IMultiDiffEditorModel } from 'vs/editor/browser/widget/multiDiffEditor/model';
import { IMultiDiffEditorViewState, IMultiDiffResource, MultiDiffEditorWidgetImpl } from 'vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl';
import { IMultiDiffEditorViewState, IMultiDiffResourceId, MultiDiffEditorWidgetImpl } from 'vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl';
import { MultiDiffEditorViewModel } from './multiDiffEditorViewModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import './colors';
@ -46,7 +46,7 @@ export class MultiDiffEditorWidget extends Disposable {
this._register(recomputeInitiallyAndOnChange(this._widgetImpl));
}
public reveal(resource: IMultiDiffResource, options?: RevealOptions): void {
public reveal(resource: IMultiDiffResourceId, options?: RevealOptions): void {
this._widgetImpl.get().reveal(resource, options);
}

View file

@ -28,6 +28,7 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle
import { DiffEditorItemTemplate, TemplateData } from './diffEditorItemTemplate';
import { DocumentDiffItemViewModel, MultiDiffEditorViewModel } from './multiDiffEditorViewModel';
import { ObjectPool } from './objectPool';
import { BugIndicatingError } from 'vs/base/common/errors';
export class MultiDiffEditorWidgetImpl extends Disposable {
private readonly _elements = h('div.monaco-component.multiDiffEditor', [
@ -191,15 +192,15 @@ export class MultiDiffEditorWidgetImpl extends Disposable {
this._scrollableElement.setScrollPosition({ scrollLeft: scrollState.left, scrollTop: scrollState.top });
}
public reveal(resource: IMultiDiffResource, options?: RevealOptions): void {
public reveal(resource: IMultiDiffResourceId, options?: RevealOptions): void {
const viewItems = this._viewItems.get();
let searchCallback: (item: VirtualizedViewItem) => boolean;
if ('original' in resource) {
searchCallback = (item) => item.viewModel.originalUri?.toString() === resource.original.toString();
} else {
searchCallback = (item) => item.viewModel.modifiedUri?.toString() === resource.modified.toString();
const index = viewItems.findIndex(
(item) => item.viewModel.originalUri?.toString() === resource.original?.toString()
&& item.viewModel.modifiedUri?.toString() === resource.modified?.toString()
);
if (index === -1) {
throw new BugIndicatingError('Resource not found in diff editor');
}
const index = viewItems.findIndex(searchCallback);
let scrollTop = 0;
for (let i = 0; i < index; i++) {
scrollTop += viewItems[i].contentHeight.get() + this._spaceBetweenPx;
@ -323,12 +324,12 @@ export interface IMultiDiffEditorOptions extends ITextEditorOptions {
export interface IMultiDiffEditorOptionsViewState {
revealData?: {
resource: IMultiDiffResource;
resource: IMultiDiffResourceId;
range?: IRange;
};
}
export type IMultiDiffResource = { original: URI } | { modified: URI };
export type IMultiDiffResourceId = { original: URI | undefined; modified: URI | undefined };
class VirtualizedViewItem extends Disposable {
private readonly _templateRef = this._register(disposableObservableValue<IReference<DiffEditorItemTemplate> | undefined>(this, undefined));

View file

@ -2760,7 +2760,7 @@ export type EditorLightbulbOptions = Readonly<Required<IEditorLightbulbOptions>>
class EditorLightbulb extends BaseEditorOption<EditorOption.lightbulb, IEditorLightbulbOptions, EditorLightbulbOptions> {
constructor() {
const defaults: EditorLightbulbOptions = { enabled: ShowLightbulbIconMode.OnCode };
const defaults: EditorLightbulbOptions = { enabled: ShowLightbulbIconMode.On };
super(
EditorOption.lightbulb, 'lightbulb', defaults,
{

View file

@ -11,8 +11,11 @@ import { getLineRangeMapping } from 'vs/editor/common/diff/defaultLinesDiffCompu
import { LinesSliceCharSequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence';
import { MyersDiffAlgorithm } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/myersDiffAlgorithm';
import { DynamicProgrammingDiffing } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/dynamicProgrammingDiffing';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
suite('myers', () => {
ensureNoDisposablesAreLeakedInTestSuite();
test('1', () => {
const s1 = new LinesSliceCharSequence(['hello world'], new OffsetRange(0, 1), true);
const s2 = new LinesSliceCharSequence(['hallo welt'], new OffsetRange(0, 1), true);
@ -23,6 +26,8 @@ suite('myers', () => {
});
suite('lineRangeMapping', () => {
ensureNoDisposablesAreLeakedInTestSuite();
test('Simple', () => {
assert.deepStrictEqual(
getLineRangeMapping(
@ -68,6 +73,8 @@ suite('lineRangeMapping', () => {
});
suite('LinesSliceCharSequence', () => {
ensureNoDisposablesAreLeakedInTestSuite();
const sequence = new LinesSliceCharSequence(
[
'line1: foo',

View file

@ -12,8 +12,11 @@ import { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping';
import { LegacyLinesDiffComputer } from 'vs/editor/common/diff/legacyLinesDiffComputer';
import { DefaultLinesDiffComputer } from 'vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer';
import { Range } from 'vs/editor/common/core/range';
import { ensureNoDisposablesAreLeakedInTestSuite } from 'vs/base/test/common/utils';
suite('diffing fixtures', () => {
ensureNoDisposablesAreLeakedInTestSuite();
setup(() => {
setUnexpectedErrorHandler(e => {
throw e;

View file

@ -130,9 +130,9 @@ class ActionItemRenderer<T> implements IListRenderer<IActionListItem<T>, IAction
data.container.title = element.label;
} else if (actionTitle && previewTitle) {
if (this._supportsPreview && element.canPreview) {
data.container.title = localize({ key: 'label-preview', comment: ['placeholders are keybindings, e.g "F2 to apply, Shift+F2 to preview"'] }, "{0} to apply, {1} to preview", actionTitle, previewTitle);
data.container.title = localize({ key: 'label-preview', comment: ['placeholders are keybindings, e.g "F2 to Apply, Shift+F2 to Preview"'] }, "{0} to Apply, {1} to Preview", actionTitle, previewTitle);
} else {
data.container.title = localize({ key: 'label', comment: ['placeholder is a keybinding, e.g "F2 to apply"'] }, "{0} to apply", actionTitle);
data.container.title = localize({ key: 'label', comment: ['placeholder is a keybinding, e.g "F2 to Apply"'] }, "{0} to Apply", actionTitle);
}
} else {
data.container.title = '';

View file

@ -14,6 +14,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener';
import 'vs/css!./link';
import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/hover/updatableHoverWidget';
import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';
import { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';
export interface ILinkDescriptor {
readonly label: string | HTMLElement;
@ -24,6 +25,7 @@ export interface ILinkDescriptor {
export interface ILinkOptions {
readonly opener?: (href: string) => void;
readonly hoverDelegate?: IHoverDelegate;
readonly textLinkForeground?: string;
}
@ -31,6 +33,7 @@ export class Link extends Disposable {
private el: HTMLAnchorElement;
private hover?: ICustomHover;
private hoverDelegate: IHoverDelegate;
private _enabled: boolean = true;
@ -90,6 +93,7 @@ export class Link extends Disposable {
href: _link.href,
}, _link.label));
this.hoverDelegate = options.hoverDelegate ?? getDefaultHoverDelegate('mouse');
this.setTooltip(_link.title);
this.el.setAttribute('role', 'button');
@ -122,8 +126,10 @@ export class Link extends Disposable {
}
private setTooltip(title: string | undefined): void {
if (!this.hover && title) {
this.hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.el, title));
if (this.hoverDelegate.showNativeHover) {
this.el.title = title ?? '';
} else if (!this.hover && title) {
this.hover = this._register(setupCustomHover(this.hoverDelegate, this.el, title));
} else if (this.hover) {
this.hover.update(title);
}

View file

@ -707,6 +707,10 @@ export class QuickInputTree extends Disposable {
// Elements that apply to the current set of elements
private _elementDisposable = this._register(new DisposableStore());
private _lastHover: IHoverWidget | undefined;
// This is used to prevent setting the checked state of a single element from firing the checked events
// so that we can batch them together. This can probably be improved by handling events differently,
// but this works for now. An observable would probably be ideal for this.
private _shouldFireCheckedEvents = true;
constructor(
private parent: HTMLElement,
@ -1056,12 +1060,18 @@ export class QuickInputTree extends Disposable {
}
setAllVisibleChecked(checked: boolean) {
this._itemElements.forEach(element => {
if (!element.hidden && !element.checkboxDisabled) {
element.checked = checked;
}
});
this._fireCheckedEvents();
try {
this._shouldFireCheckedEvents = false;
this._itemElements.forEach(element => {
if (!element.hidden && !element.checkboxDisabled) {
// Would fire an event if we didn't have the flag set
element.checked = checked;
}
});
} finally {
this._shouldFireCheckedEvents = true;
this._fireCheckedEvents();
}
}
setElements(inputElements: QuickPickItem[]): void {
@ -1185,14 +1195,20 @@ export class QuickInputTree extends Disposable {
}
setCheckedElements(items: IQuickPickItem[]) {
const checked = new Set();
for (const item of items) {
checked.add(item);
try {
this._shouldFireCheckedEvents = false;
const checked = new Set();
for (const item of items) {
checked.add(item);
}
for (const element of this._itemElements) {
// Would fire an event if we didn't have the flag set
element.checked = checked.has(element.item);
}
} finally {
this._shouldFireCheckedEvents = true;
this._fireCheckedEvents();
}
for (const element of this._itemElements) {
element.checked = checked.has(element.item);
}
this._fireCheckedEvents();
}
focus(what: QuickInputListFocus): void {
@ -1276,9 +1292,9 @@ export class QuickInputTree extends Disposable {
if (e.element instanceof QuickPickSeparatorElement) {
foundSeparatorAsItem = true;
// If the separator is visible, then we should just focus it.
// If the separator is visible, then we should just reveal its first child so it's not as jarring.
if (this._separatorRenderer.isSeparatorVisible(e.element)) {
this._tree.reveal(e.element);
this._tree.reveal(e.element.children[0]);
} else {
// If the separator is not visible, then we should
// push it up to the top of the list.
@ -1498,14 +1514,20 @@ export class QuickInputTree extends Disposable {
}
toggleCheckbox() {
const elements = this._tree.getFocus().filter((e): e is QuickPickItemElement => e instanceof QuickPickItemElement);
const allChecked = this._allVisibleChecked(elements);
for (const element of elements) {
if (!element.checkboxDisabled) {
element.checked = !allChecked;
try {
this._shouldFireCheckedEvents = false;
const elements = this._tree.getFocus().filter((e): e is QuickPickItemElement => e instanceof QuickPickItemElement);
const allChecked = this._allVisibleChecked(elements);
for (const element of elements) {
if (!element.checkboxDisabled) {
// Would fire an event if we didn't have the flag set
element.checked = !allChecked;
}
}
} finally {
this._shouldFireCheckedEvents = true;
this._fireCheckedEvents();
}
this._fireCheckedEvents();
}
display(display: boolean) {
@ -1565,6 +1587,9 @@ export class QuickInputTree extends Disposable {
}
private _fireCheckedEvents() {
if (!this._shouldFireCheckedEvents) {
return;
}
this._onChangedAllVisibleChecked.fire(this.getAllVisibleChecked());
this._onChangedCheckedCount.fire(this.getCheckedCount());
this._onChangedCheckedElements.fire(this.getCheckedElements());

View file

@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
// Import the effects we need
import { Color } from 'vs/base/common/color';
import { registerColor, darken, lighten, ifDefinedThenElse, transparent } from 'vs/platform/theme/common/colorUtils';
import { registerColor, darken, lighten, transparent, ifDefinedThenElse } from 'vs/platform/theme/common/colorUtils';
// Import the colors we need
import { foreground, contrastBorder, activeContrastBorder, focusBorder, iconForeground } from 'vs/platform/theme/common/colors/baseColors';

View file

@ -267,7 +267,8 @@ export abstract class AbstractTextEditor<T extends IEditorViewState> extends Abs
}
return {
scrollTop: editor.getScrollTop(),
// The top position can vary depending on the view zones (find widget for example)
scrollTop: editor.getScrollTop() - editor.getTopForLineNumber(1),
scrollLeft: editor.getScrollLeft(),
};
}

View file

@ -109,6 +109,8 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
{
type: 'string',
markdownDescription: localize('workbench.editor.label.template', "The template which should be rendered when the pattern mtches. May include the variables ${dirname}, ${filename} and ${extname}."),
minLength: 1,
pattern: '.*[a-zA-Z0-9].*'
},
'default': {}
},

View file

@ -37,8 +37,9 @@ import { ButtonBar } from 'vs/base/browser/ui/button/button';
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles';
import { Mutable } from 'vs/base/common/types';
import { IResourceDiffEditorInput } from 'vs/workbench/common/editor';
import { IMultiDiffEditorOptions } from 'vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl';
import { IMultiDiffEditorOptions, IMultiDiffResourceId } from 'vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl';
import { IRange } from 'vs/editor/common/core/range';
import { CachedFunction, LRUCachedFunction } from 'vs/base/common/cache';
const enum State {
Data = 'data',
@ -70,8 +71,6 @@ export class BulkEditPane extends ViewPane {
private _currentResolve?: (edit?: ResourceEdit[]) => void;
private _currentInput?: BulkFileOperations;
private _currentProvider?: BulkEditPreviewProvider;
private _fileOperations?: BulkFileOperation[];
private _resources?: IResourceDiffEditorInput[];
constructor(
options: IViewletViewOptions,
@ -345,12 +344,13 @@ export class BulkEditPane extends ViewPane {
return;
}
const resources = await this._resolveResources(fileOperations);
const result = await this._computeResourceDiffEditorInputs.get(fileOperations);
const resourceId = await result.getResourceDiffEditorInputIdOfOperation(fileElement.edit);
const options: Mutable<IMultiDiffEditorOptions> = {
...e.editorOptions,
viewState: {
revealData: {
resource: { original: fileElement.edit.uri },
resource: resourceId,
range: selection,
}
}
@ -359,49 +359,56 @@ export class BulkEditPane extends ViewPane {
const label = 'Refactor Preview';
this._editorService.openEditor({
multiDiffSource,
resources,
label,
options,
isTransient: true,
description: label
description: label,
resources: result.resources
}, e.sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
}
private async _resolveResources(fileOperations: BulkFileOperation[]): Promise<IResourceDiffEditorInput[]> {
if (this._fileOperations === fileOperations && this._resources) {
return this._resources;
}
const sortedFileOperations = fileOperations.sort(compareBulkFileOperations);
const resources: IResourceDiffEditorInput[] = [];
for (const operation of sortedFileOperations) {
const operationUri = operation.uri;
const previewUri = this._currentProvider!.asPreviewUri(operationUri);
// delete -> show single editor
if (operation.type & BulkFileOperationType.Delete) {
resources.push({
original: { resource: undefined },
modified: { resource: URI.revive(previewUri) }
});
private readonly _computeResourceDiffEditorInputs = new LRUCachedFunction(async (fileOperations: BulkFileOperation[]) => {
const computeDiffEditorInput = new CachedFunction<BulkFileOperation, Promise<IResourceDiffEditorInput>>(async (fileOperation) => {
const fileOperationUri = fileOperation.uri;
const previewUri = this._currentProvider!.asPreviewUri(fileOperationUri);
// delete
if (fileOperation.type & BulkFileOperationType.Delete) {
return {
original: { resource: URI.revive(previewUri) },
modified: { resource: undefined }
};
} else {
// rename, create, edits -> show diff editr
}
// rename, create, edits
else {
let leftResource: URI | undefined;
try {
(await this._textModelService.createModelReference(operationUri)).dispose();
leftResource = operationUri;
(await this._textModelService.createModelReference(fileOperationUri)).dispose();
leftResource = fileOperationUri;
} catch {
leftResource = BulkEditPreviewProvider.emptyPreview;
}
resources.push({
return {
original: { resource: URI.revive(leftResource) },
modified: { resource: URI.revive(previewUri) }
});
};
}
});
const sortedFileOperations = fileOperations.slice().sort(compareBulkFileOperations);
const resources: IResourceDiffEditorInput[] = [];
for (const operation of sortedFileOperations) {
resources.push(await computeDiffEditorInput.get(operation));
}
this._fileOperations = fileOperations;
this._resources = resources;
return resources;
}
const getResourceDiffEditorInputIdOfOperation = async (operation: BulkFileOperation): Promise<IMultiDiffResourceId> => {
const resource = await computeDiffEditorInput.get(operation);
return { original: resource.original.resource, modified: resource.modified.resource };
};
return {
resources,
getResourceDiffEditorInputIdOfOperation
};
}, key => key);
private _onContextMenu(e: ITreeContextMenuEvent<any>): void {

View file

@ -193,7 +193,7 @@ export function registerChatCodeBlockActions() {
when: ContextKeyExpr.or(ContextKeyExpr.and(CONTEXT_IN_CHAT_SESSION, CONTEXT_IN_CHAT_INPUT.negate()), accessibleViewInCodeBlock),
primary: KeyMod.CtrlCmd | KeyCode.Enter,
mac: { primary: KeyMod.WinCtrl | KeyCode.Enter },
weight: KeybindingWeight.WorkbenchContrib
weight: KeybindingWeight.ExternalExtension + 1
},
});
}

View file

@ -98,6 +98,7 @@ export interface IChatWidgetViewOptions {
inputSideToolbar?: MenuId;
telemetrySource?: string;
};
defaultElementHeight?: number;
editorOverflowWidgetsDomNode?: HTMLElement;
}
@ -115,6 +116,7 @@ export interface IChatWidget {
readonly onDidChangeViewModel: Event<void>;
readonly onDidAcceptInput: Event<void>;
readonly onDidSubmitAgent: Event<{ agent: IChatAgentData; slashCommand?: IChatAgentCommand }>;
readonly onDidChangeParsedInput: Event<void>;
readonly location: ChatAgentLocation;
readonly viewContext: IChatWidgetViewContext;
readonly viewModel: IChatViewModel | undefined;

View file

@ -452,10 +452,10 @@ export class ChatInputPart extends Disposable implements IHistoryNavigationWidge
private _layout(height: number, width: number, allowRecurse = true): void {
const followupsHeight = this.followupsContainer.offsetHeight;
const inputPartBorder = 1;
const inputPartBorder = 0;
const inputPartHorizontalPadding = this.options.renderStyle === 'compact' ? 8 : 40;
const inputPartVerticalPadding = this.options.renderStyle === 'compact' ? 12 : 24;
const inputEditorHeight = Math.min(this._inputEditor.getContentHeight(), height - followupsHeight - inputPartHorizontalPadding - inputPartBorder, INPUT_EDITOR_MAX_HEIGHT);
const inputEditorHeight = Math.min(this._inputEditor.getContentHeight(), height - followupsHeight - inputPartVerticalPadding - inputPartBorder, INPUT_EDITOR_MAX_HEIGHT);
const implicitContextHeight = this.implicitContextContainer.offsetHeight;
const inputEditorBorder = 2;

View file

@ -25,7 +25,7 @@ import { ResourceMap } from 'vs/base/common/map';
import { FileAccess, Schemas, matchesSomeScheme } from 'vs/base/common/network';
import { clamp } from 'vs/base/common/numbers';
import { basename } from 'vs/base/common/path';
import { basenameOrAuthority, dirname } from 'vs/base/common/resources';
import { basenameOrAuthority } from 'vs/base/common/resources';
import { equalsIgnoreCase } from 'vs/base/common/strings';
import { ThemeIcon } from 'vs/base/common/themables';
import { URI } from 'vs/base/common/uri';
@ -33,7 +33,7 @@ import { IMarkdownRenderResult, MarkdownRenderer } from 'vs/editor/browser/widge
import { Range } from 'vs/editor/common/core/range';
import { IResolvedTextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';
import { localize } from 'vs/nls';
import { IMenuEntryActionViewItemOptions, MenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IMenuEntryActionViewItemOptions, MenuEntryActionViewItem, createActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar';
import { MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
import { ICommandService } from 'vs/platform/commands/common/commands';
@ -42,7 +42,6 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { FileKind, FileType } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ILabelService } from 'vs/platform/label/common/label';
import { WorkbenchCompressibleAsyncDataTree, WorkbenchList } from 'vs/platform/list/browser/listService';
import { ILogService } from 'vs/platform/log/common/log';
import { IOpenerService } from 'vs/platform/opener/common/opener';
@ -269,12 +268,14 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
menuOptions: {
shouldForwardArgs: true
},
toolbarOptions: {
shouldInlineSubmenu: submenu => submenu.actions.length <= 1
},
actionViewItemProvider: (action: IAction, options: IActionViewItemOptions) => {
if (action instanceof MenuItemAction && (action.item.id === 'workbench.action.chat.voteDown' || action.item.id === 'workbench.action.chat.voteUp')) {
return scopedInstantiationService.createInstance(ChatVoteButton, action, options as IMenuEntryActionViewItemOptions);
}
return undefined;
return createActionViewItem(scopedInstantiationService, action, options);
}
}));
}
@ -495,7 +496,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
}
}
if (madeChanges) {
dom.append(templateData.value, $('.interactive-edits-summary', undefined, localize('editsSummary', "Made text edits")));
dom.append(templateData.value, $('.interactive-edits-summary', undefined, localize('editsSummary', "Made changes.")));
}
}
@ -513,6 +514,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
private renderWelcomeMessage(element: IChatWelcomeMessageViewModel, templateData: IChatListItemTemplate) {
dom.clearNode(templateData.value);
dom.clearNode(templateData.referencesListContainer);
dom.hide(templateData.referencesListContainer);
for (const item of element.content) {
if (Array.isArray(item)) {
@ -814,7 +816,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
editorOptions: {
...e.editorOptions,
...{
selection: 'range' in e.element.reference ? e.element.reference.range : undefined
selection: uriOrLocation && 'range' in uriOrLocation ? uriOrLocation.range : undefined
}
}
});
@ -916,17 +918,13 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
}
const sessionId = isResponseVM(element) || isRequestVM(element) ? element.sessionId : '';
const modelEntry = this.codeBlockModelCollection.get(sessionId, element, index);
if (!modelEntry) {
console.error('Trying to render code block without model', element.id, index);
return $('div');
}
const modelEntry = this.codeBlockModelCollection.getOrCreate(sessionId, element, index);
vulns = modelEntry.vulns;
textModel = modelEntry.model;
}
const hideToolbar = isResponseVM(element) && element.errorDetails?.responseIsFiltered;
const ref = this.renderCodeBlock({ languageId, textModel, codeBlockIndex: index, element, range, hideToolbar, parentContextKeyService: templateData.contextKeyService, vulns });
const ref = this.renderCodeBlock({ languageId, textModel, codeBlockIndex: index, element, range, hideToolbar, parentContextKeyService: templateData.contextKeyService, vulns }, text);
// Attach this after updating text/layout of the editor, so it should only be fired when the size updates later (horizontal scrollbar, wrapping)
// not during a renderElement OR a progressive render (when we will be firing this event anyway at the end of the render)
@ -973,9 +971,13 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
};
}
private renderCodeBlock(data: ICodeBlockData): IDisposableReference<CodeBlockPart> {
private renderCodeBlock(data: ICodeBlockData, text: string): IDisposableReference<CodeBlockPart> {
const ref = this._editorPool.get();
const editorInfo = ref.object;
if (isResponseVM(data.element)) {
this.codeBlockModelCollection.update(data.element.sessionId, data.element, data.codeBlockIndex, { text, languageId: data.languageId });
}
editorInfo.render(data, this._currentLayoutWidth, this.rendererOptions.editableCodeBlock);
return ref;
@ -1010,6 +1012,7 @@ export class ChatListItemRenderer extends Disposable implements ITreeRenderer<Ch
export class ChatListDelegate implements IListVirtualDelegate<ChatTreeItem> {
constructor(
private readonly defaultElementHeight: number,
@ILogService private readonly logService: ILogService
) { }
@ -1023,7 +1026,7 @@ export class ChatListDelegate implements IListVirtualDelegate<ChatTreeItem> {
getHeight(element: ChatTreeItem): number {
const kind = isRequestVM(element) ? 'request' : 'response';
const height = ('currentRenderedHeight' in element ? element.currentRenderedHeight : undefined) ?? 200;
const height = ('currentRenderedHeight' in element ? element.currentRenderedHeight : undefined) ?? this.defaultElementHeight;
this._traceLayout('getHeight', `${kind}, height=${height}`);
return height;
}
@ -1223,7 +1226,6 @@ class ContentReferencesListRenderer implements IListRenderer<IChatContentReferen
constructor(
private labels: ResourceLabels,
@ILabelService private readonly labelService: ILabelService,
@IChatVariablesService private readonly chatVariablesService: IChatVariablesService,
) { }
@ -1237,19 +1239,17 @@ class ContentReferencesListRenderer implements IListRenderer<IChatContentReferen
const reference = data.reference;
templateData.label.element.style.display = 'flex';
if ('variableName' in reference) {
const variable = this.chatVariablesService.getVariable(reference.variableName);
if (reference.value) {
const uri = URI.isUri(reference.value) ? reference.value : reference.value.uri;
const title = this.labelService.getUriLabel(dirname(uri), { relative: true });
templateData.label.setResource(
{
resource: uri,
name: basenameOrAuthority(uri),
description: `#${reference.variableName}`,
range: 'range' in reference.value ? reference.value.range : undefined
},
{ title, descriptionTitle: variable?.description });
});
} else {
const variable = this.chatVariablesService.getVariable(reference.variableName);
templateData.label.setLabel(`#${reference.variableName}`, undefined, { title: variable?.description });
}
} else {

View file

@ -32,7 +32,7 @@ import { ChatListDelegate, ChatListItemRenderer, IChatListItemRendererOptions, I
import { ChatEditorOptions } from 'vs/workbench/contrib/chat/browser/chatOptions';
import { ChatViewPane } from 'vs/workbench/contrib/chat/browser/chatViewPane';
import { ChatAgentLocation, IChatAgentCommand, IChatAgentData, IChatAgentService } from 'vs/workbench/contrib/chat/common/chatAgents';
import { CONTEXT_CHAT_INPUT_HAS_AGENT, CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION, CONTEXT_RESPONSE_FILTERED } from 'vs/workbench/contrib/chat/common/chatContextKeys';
import { CONTEXT_CHAT_INPUT_HAS_AGENT, CONTEXT_CHAT_LOCATION, CONTEXT_CHAT_REQUEST_IN_PROGRESS, CONTEXT_IN_CHAT_SESSION, CONTEXT_RESPONSE_FILTERED } from 'vs/workbench/contrib/chat/common/chatContextKeys';
import { IChatContributionService } from 'vs/workbench/contrib/chat/common/chatContributionService';
import { ChatModelInitState, IChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
import { ChatRequestAgentPart, IParsedChatRequest, chatAgentLeader, chatSubcommandLeader, extractAgentAndCommand } from 'vs/workbench/contrib/chat/common/chatParserTypes';
@ -97,9 +97,15 @@ export class ChatWidget extends Disposable implements IChatWidget {
private _onDidAcceptInput = this._register(new Emitter<void>());
readonly onDidAcceptInput = this._onDidAcceptInput.event;
private _onDidChangeParsedInput = this._register(new Emitter<void>());
readonly onDidChangeParsedInput = this._onDidChangeParsedInput.event;
private _onDidChangeHeight = this._register(new Emitter<number>());
readonly onDidChangeHeight = this._onDidChangeHeight.event;
private readonly _onDidChangeContentHeight = new Emitter<void>();
readonly onDidChangeContentHeight: Event<void> = this._onDidChangeContentHeight.event;
private contribs: IChatWidgetContrib[] = [];
private tree!: WorkbenchObjectTree<ChatTreeItem>;
@ -175,6 +181,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
) {
super();
CONTEXT_IN_CHAT_SESSION.bindTo(contextKeyService).set(true);
CONTEXT_CHAT_LOCATION.bindTo(contextKeyService).set(location);
this.agentInInput = CONTEXT_CHAT_INPUT_HAS_AGENT.bindTo(contextKeyService);
this.requestInProgress = CONTEXT_CHAT_REQUEST_IN_PROGRESS.bindTo(contextKeyService);
@ -221,7 +228,9 @@ export class ChatWidget extends Disposable implements IChatWidget {
private _lastSelectedAgent: IChatAgentData | undefined;
set lastSelectedAgent(agent: IChatAgentData | undefined) {
this.parsedChatRequest = undefined;
this._lastSelectedAgent = agent;
this._onDidChangeParsedInput.fire();
}
get lastSelectedAgent(): IChatAgentData | undefined {
@ -396,7 +405,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
private createList(listContainer: HTMLElement, options: IChatListItemRendererOptions): void {
const scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection([IContextKeyService, this.contextKeyService]));
const delegate = scopedInstantiationService.createInstance(ChatListDelegate);
const delegate = scopedInstantiationService.createInstance(ChatListDelegate, this.viewOptions.defaultElementHeight ?? 200);
const rendererDelegate: IChatRendererDelegate = {
getListLength: () => this.tree.getNode(null).visibleChildrenCount,
onDidScroll: this.onDidScroll,
@ -499,6 +508,7 @@ export class ChatWidget extends Disposable implements IChatWidget {
}
this.previousTreeScrollHeight = this.tree.scrollHeight;
this._onDidChangeContentHeight.fire();
}
private createInput(container: HTMLElement, options?: { renderFollowups: boolean; renderStyle?: 'default' | 'compact' }): void {
@ -557,7 +567,12 @@ export class ChatWidget extends Disposable implements IChatWidget {
},
});
}));
this._register(this.inputPart.onDidChangeHeight(() => this.bodyDimension && this.layout(this.bodyDimension.height, this.bodyDimension.width)));
this._register(this.inputPart.onDidChangeHeight(() => {
if (this.bodyDimension) {
this.layout(this.bodyDimension.height, this.bodyDimension.width);
}
this._onDidChangeContentHeight.fire();
}));
this._register(this.inputEditor.onDidChangeModelContent(() => this.updateImplicitContextKinds()));
this._register(this.chatAgentService.onDidChangeAgents(() => {
if (this.viewModel) {

View file

@ -44,6 +44,7 @@ import { MenuPreventer } from 'vs/workbench/contrib/codeEditor/browser/menuPreve
import { SelectionClipboardContributionID } from 'vs/workbench/contrib/codeEditor/browser/selectionClipboard';
import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
import { IMarkdownVulnerability } from '../common/annotations';
import { TabFocus } from 'vs/editor/browser/config/tabFocus';
const $ = dom.$;
@ -334,6 +335,10 @@ export class CodeBlockPart extends Disposable {
await this.updateEditor(data);
this.layout(width);
if (editable) {
this._register(this.editor.onDidFocusEditorWidget(() => TabFocus.setTabFocusMode(true)));
this._register(this.editor.onDidBlurEditorWidget(() => TabFocus.setTabFocusMode(false)));
}
this.editor.updateOptions({ ariaLabel: localize('chat.codeBlockLabel', "Code block {0}", data.codeBlockIndex + 1), readOnly: !editable });
if (data.hideToolbar) {

View file

@ -66,6 +66,7 @@ class InputEditorDecorations extends Disposable {
this.updateInputEditorDecorations();
this._register(this.widget.inputEditor.onDidChangeModelContent(() => this.updateInputEditorDecorations()));
this._register(this.widget.onDidChangeParsedInput(() => this.updateInputEditorDecorations()));
this._register(this.widget.onDidChangeViewModel(() => {
this.registerViewModelListeners();
this.previouslyUsedAgents.clear();
@ -211,7 +212,9 @@ class InputEditorDecorations extends Disposable {
const textDecorations: IDecorationOptions[] | undefined = [];
if (agentPart) {
const agentHover = `(${agentPart.agent.name}) ${agentPart.agent.description}`;
const isDupe = !!this.chatAgentService.getAgents().find(other => other.name === agentPart.agent.name && other.id !== agentPart.agent.id);
const id = isDupe ? `(${agentPart.agent.id}) ` : '';
const agentHover = `${id}${agentPart.agent.description}`;
textDecorations.push({ range: agentPart.editorRange, hoverMessage: new MarkdownString(agentHover) });
if (agentSubcommandPart) {
textDecorations.push({ range: agentSubcommandPart.editorRange, hoverMessage: new MarkdownString(agentSubcommandPart.command.description) });
@ -456,7 +459,8 @@ class AgentCompletions extends Disposable {
insertText: `${agentLabel} `,
range: new Range(1, 1, 1, 1),
kind: CompletionItemKind.Text,
sortText: `${chatSubcommandLeader}${agent.name}`,
sortText: `${chatSubcommandLeader}${agent.id}`,
command: { id: AssignSelectedAgentAction.ID, title: AssignSelectedAgentAction.ID, arguments: [{ agent, widget } satisfies AssignSelectedAgentActionArgs] },
};
});
@ -473,7 +477,8 @@ class AgentCompletions extends Disposable {
detail: `(${agentLabel}) ${c.description ?? ''}`,
range: new Range(1, 1, 1, 1),
kind: CompletionItemKind.Text, // The icons are disabled here anyway
sortText: `${chatSubcommandLeader}${agent.name}${c.name}`,
sortText: `${chatSubcommandLeader}${agent.id}${c.name}`,
command: { id: AssignSelectedAgentAction.ID, title: AssignSelectedAgentAction.ID, arguments: [{ agent, widget } satisfies AssignSelectedAgentActionArgs] },
} satisfies CompletionItem;
})))
};

View file

@ -166,6 +166,11 @@
background-color: var(--vscode-chat-list-background);
}
.interactive-item-container.interactive-request .header .monaco-toolbar {
/* Take the partially-transparent background color override for request rows */
background-color: inherit;
}
.interactive-item-container .header .monaco-toolbar .checked.action-label,
.interactive-item-container .header .monaco-toolbar .checked.action-label:hover {
color: var(--vscode-inputOption-activeForeground) !important;
@ -348,6 +353,10 @@
justify-content: space-between;
}
.interactive-session .interactive-input-part.compact .interactive-input-and-execute-toolbar {
margin-bottom: 0;
}
.interactive-session .interactive-input-and-side-toolbar {
display: flex;
gap: 4px;

View file

@ -5,6 +5,7 @@
import { localize } from 'vs/nls';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
export const CONTEXT_RESPONSE_VOTE = new RawContextKey<string>('chatSessionResponseVote', '', { type: 'string', description: localize('interactiveSessionResponseVote', "When the response has been voted up, is set to 'up'. When voted down, is set to 'down'. Otherwise an empty string.") });
export const CONTEXT_RESPONSE_DETECTED_AGENT_COMMAND = new RawContextKey<boolean>('chatSessionResponseDetectedAgentOrCommand', false, { type: 'boolean', description: localize('chatSessionResponseDetectedAgentOrCommand', "When the agent or command was automatically detected") });
@ -23,3 +24,4 @@ export const CONTEXT_IN_CHAT_SESSION = new RawContextKey<boolean>('inChat', fals
export const CONTEXT_PROVIDER_EXISTS = new RawContextKey<boolean>('hasChatProvider', false, { type: 'boolean', description: localize('hasChatProvider', "True when some chat provider has been registered.") });
export const CONTEXT_CHAT_INPUT_CURSOR_AT_TOP = new RawContextKey<boolean>('chatCursorAtTop', false);
export const CONTEXT_CHAT_INPUT_HAS_AGENT = new RawContextKey<boolean>('chatInputHasAgent', false);
export const CONTEXT_CHAT_LOCATION = new RawContextKey<ChatAgentLocation>('chatLocation', undefined);

View file

@ -241,7 +241,9 @@ export class ChatViewModel extends Disposable implements IChatViewModel {
private onAddResponse(responseModel: IChatResponseModel) {
const response = this.instantiationService.createInstance(ChatResponseViewModel, responseModel);
this._register(response.onDidChange(() => {
this.updateCodeBlockTextModels(response);
if (response.isComplete) {
this.updateCodeBlockTextModels(response);
}
return this._onDidChange.fire(null);
}));
this._items.push(response);

View file

@ -53,6 +53,7 @@ import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { ProgressLocation } from 'vs/platform/progress/common/progress';
import { TerminalChatController, TerminalChatContextKeys } from 'vs/workbench/contrib/terminal/browser/terminalContribExports';
import { NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
const CONTEXT_VOICE_CHAT_GETTING_READY = new RawContextKey<boolean>('voiceChatGettingReady', false, { type: 'boolean', description: localize('voiceChatGettingReady', "True when getting ready for receiving voice input from the microphone for voice chat.") });
const CONTEXT_VOICE_CHAT_IN_PROGRESS = new RawContextKey<boolean>('voiceChatInProgress', false, { type: 'boolean', description: localize('voiceChatInProgress', "True when voice recording from microphone is in progress for voice chat.") });
@ -461,22 +462,18 @@ async function startVoiceChatWithHoldMode(id: string, accessor: ServicesAccessor
const holdMode = keybindingService.enableKeybindingHoldMode(id);
let session: IVoiceChatSession | undefined = undefined;
const controller = await VoiceChatSessionControllerFactory.create(accessor, target);
if (!controller) {
return;
}
const session = await VoiceChatSessions.getInstance(instantiationService).start(controller, context);
let acceptVoice = false;
const handle = disposableTimeout(() => {
acceptVoice = true;
session?.setTimeoutDisabled(true); // disable accept on timeout when hold mode runs for VOICE_KEY_HOLD_THRESHOLD
}, VOICE_KEY_HOLD_THRESHOLD);
const controller = await VoiceChatSessionControllerFactory.create(accessor, target);
if (!controller) {
handle.dispose();
return;
}
session = await VoiceChatSessions.getInstance(instantiationService).start(controller, context);
await holdMode;
handle.dispose();
@ -524,7 +521,8 @@ export class HoldToVoiceChatInChatViewAction extends Action2 {
when: ContextKeyExpr.and(
CanVoiceChat,
FocusInChatInput.negate(), // when already in chat input, disable this action and prefer to start voice chat directly
EditorContextKeys.focus.negate() // do not steal the inline-chat keybinding
EditorContextKeys.focus.negate(), // do not steal the inline-chat keybinding
NOTEBOOK_EDITOR_FOCUSED.negate() // do not steal the notebook keybinding
),
primary: KeyMod.CtrlCmd | KeyCode.KeyI
}
@ -607,6 +605,7 @@ export class StartVoiceChatAction extends Action2 {
when: ContextKeyExpr.and(
FocusInChatInput, // scope this action to chat input fields only
EditorContextKeys.focus.negate(), // do not steal the inline-chat keybinding
NOTEBOOK_EDITOR_FOCUSED.negate(), // do not steal the notebook keybinding
CONTEXT_VOICE_CHAT_IN_VIEW_IN_PROGRESS.negate(),
CONTEXT_QUICK_VOICE_CHAT_IN_PROGRESS.negate(),
CONTEXT_VOICE_CHAT_IN_EDITOR_IN_PROGRESS.negate(),

View file

@ -249,7 +249,7 @@ export class EditorDictation extends Disposable implements IEditorContribution {
const cts = new CancellationTokenSource();
disposables.add(toDisposable(() => cts.dispose(true)));
const session = await this.speechService.createSpeechToTextSession(cts.token);
const session = await this.speechService.createSpeechToTextSession(cts.token, 'editor');
disposables.add(session.onDidChange(e => {
if (cts.token.isCancellationRequested) {
return;

View file

@ -11,7 +11,7 @@ import { EmbeddedDiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/em
import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/embeddedCodeEditorWidget';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { InlineChatController, InlineChatRunOptions } from 'vs/workbench/contrib/inlineChat/browser/inlineChatController';
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_HAS_PROVIDER, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_EMPTY, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_VISIBLE, MENU_INLINE_CHAT_WIDGET_DISCARD, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_EDIT_MODE, EditMode, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, MENU_INLINE_CHAT_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, CTX_INLINE_CHAT_RESPONSE_TYPES, InlineChatResponseTypes, ACTION_VIEW_IN_CHAT, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_RESPONSE_FOCUSED, CTX_INLINE_CHAT_SUPPORT_ISSUE_REPORTING, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, MENU_INLINE_CHAT_WIDGET } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { CTX_INLINE_CHAT_FOCUSED, CTX_INLINE_CHAT_HAS_PROVIDER, CTX_INLINE_CHAT_INNER_CURSOR_FIRST, CTX_INLINE_CHAT_INNER_CURSOR_LAST, CTX_INLINE_CHAT_EMPTY, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, CTX_INLINE_CHAT_VISIBLE, MENU_INLINE_CHAT_WIDGET_DISCARD, MENU_INLINE_CHAT_WIDGET_STATUS, CTX_INLINE_CHAT_EDIT_MODE, EditMode, CTX_INLINE_CHAT_DOCUMENT_CHANGED, CTX_INLINE_CHAT_DID_EDIT, CTX_INLINE_CHAT_HAS_STASHED_SESSION, MENU_INLINE_CHAT_WIDGET_FEEDBACK, ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, CTX_INLINE_CHAT_RESPONSE_TYPES, InlineChatResponseTypes, ACTION_VIEW_IN_CHAT, CTX_INLINE_CHAT_USER_DID_EDIT, CTX_INLINE_CHAT_RESPONSE_FOCUSED, CTX_INLINE_CHAT_SUPPORT_ISSUE_REPORTING, InlineChatResponseFeedbackKind, CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF, CTX_INLINE_CHAT_CHANGE_HAS_DIFF, MENU_INLINE_CHAT_WIDGET, ACTION_TOGGLE_DIFF } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { localize, localize2 } from 'vs/nls';
import { Action2, IAction2Options, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
@ -32,7 +32,8 @@ import { AccessibilityHelpAction } from 'vs/workbench/contrib/accessibility/brow
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { ILogService } from 'vs/platform/log/common/log';
import { CONTEXT_RESPONSE, CONTEXT_RESPONSE_DETECTED_AGENT_COMMAND } from 'vs/workbench/contrib/chat/common/chatContextKeys';
import { CONTEXT_CHAT_LOCATION, CONTEXT_RESPONSE, CONTEXT_RESPONSE_DETECTED_AGENT_COMMAND } from 'vs/workbench/contrib/chat/common/chatContextKeys';
import { ChatAgentLocation } from 'vs/workbench/contrib/chat/common/chatAgents';
CommandsRegistry.registerCommandAlias('interactiveEditor.start', 'inlineChat.start');
CommandsRegistry.registerCommandAlias('interactive.acceptChanges', ACTION_ACCEPT_CHANGES);
@ -170,6 +171,18 @@ export abstract class AbstractInlineChatAction extends EditorAction2 {
}
const CHAT_REGENERATE_MENU = MenuId.for('inlineChat.response.rerun');
MenuRegistry.appendMenuItem(MenuId.ChatMessageTitle, {
submenu: CHAT_REGENERATE_MENU,
title: localize('reunmenu', "Regenerate..."),
icon: Codicon.refresh,
group: 'navigation',
order: -10,
when: ContextKeyExpr.and(CONTEXT_RESPONSE, CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Editor))
});
export class ReRunRequestAction extends AbstractInlineChatAction {
constructor() {
@ -179,16 +192,16 @@ export class ReRunRequestAction extends AbstractInlineChatAction {
shortTitle: localize('rerunShort', 'Regenerate'),
icon: Codicon.refresh,
precondition: ContextKeyExpr.and(CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_EMPTY.negate(), CTX_INLINE_CHAT_RESPONSE_TYPES.notEqualsTo(InlineChatResponseTypes.Empty)),
menu: {
id: MENU_INLINE_CHAT_WIDGET_STATUS,
group: '2_feedback',
order: 3,
}
menu: [{
id: CHAT_REGENERATE_MENU,
group: 'navigation',
order: -120,
when: ContextKeyExpr.and(CONTEXT_RESPONSE, CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Editor))
}]
});
}
override runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController): void {
// ctrl.regenerate();
ctrl.rerun({ retry: true });
}
}
@ -198,13 +211,13 @@ export class ReRunRequestWithIntentDetectionAction extends AbstractInlineChatAct
constructor() {
super({
id: 'inlineChat.rerunWithIntentDetection',
title: localize('rerunWithout', 'Rerun without command detection'),
title: localize('rerunWithout', 'Regenerate without Command Detection'),
icon: Codicon.debugRestartFrame,
menu: {
id: MenuId.ChatMessageTitle,
id: CHAT_REGENERATE_MENU,
group: 'navigation',
order: -100,
when: ContextKeyExpr.and(CONTEXT_RESPONSE_DETECTED_AGENT_COMMAND, CONTEXT_RESPONSE)
when: ContextKeyExpr.and(CONTEXT_RESPONSE_DETECTED_AGENT_COMMAND, CONTEXT_RESPONSE, CONTEXT_CHAT_LOCATION.isEqualTo(ChatAgentLocation.Editor))
}
});
}
@ -394,16 +407,16 @@ export class ToggleDiffForChange extends AbstractInlineChatAction {
constructor() {
super({
id: 'inlineChat.toggleDiff',
id: ACTION_TOGGLE_DIFF,
precondition: ContextKeyExpr.and(CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Live), CTX_INLINE_CHAT_CHANGE_HAS_DIFF),
title: localize2('showChanges', 'Show Changes'),
title: localize2('showChanges', 'Toggle Changes'),
icon: Codicon.diffSingle,
toggled: {
condition: CTX_INLINE_CHAT_CHANGE_SHOWS_DIFF,
},
menu: [
{
id: MENU_INLINE_CHAT_WIDGET_FEEDBACK,
id: MENU_INLINE_CHAT_WIDGET_STATUS,
group: '1_main',
when: ContextKeyExpr.and(CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Live), CTX_INLINE_CHAT_CHANGE_HAS_DIFF)
}
@ -454,10 +467,6 @@ export class AcceptChanges extends AbstractInlineChatAction {
keybinding: [{
weight: KeybindingWeight.WorkbenchContrib + 10,
primary: KeyMod.CtrlCmd | KeyCode.Enter,
}, {
primary: KeyCode.Escape,
weight: KeybindingWeight.WorkbenchContrib,
when: CTX_INLINE_CHAT_USER_DID_EDIT
}],
menu: {
when: ContextKeyExpr.and(CTX_INLINE_CHAT_RESPONSE_TYPES.notEqualsTo(InlineChatResponseTypes.OnlyMessages)),
@ -480,7 +489,7 @@ export class CancelSessionAction extends AbstractInlineChatAction {
id: 'inlineChat.cancel',
title: localize('cancel', 'Cancel'),
icon: Codicon.clearAll,
precondition: CTX_INLINE_CHAT_VISIBLE,
precondition: ContextKeyExpr.and(CTX_INLINE_CHAT_VISIBLE, CTX_INLINE_CHAT_EDIT_MODE.isEqualTo(EditMode.Preview)),
keybinding: {
weight: KeybindingWeight.EditorContrib - 1,
primary: KeyCode.Escape
@ -510,7 +519,8 @@ export class CloseAction extends AbstractInlineChatAction {
precondition: CTX_INLINE_CHAT_VISIBLE,
keybinding: {
weight: KeybindingWeight.EditorContrib - 1,
primary: KeyCode.Escape
primary: KeyCode.Escape,
when: CTX_INLINE_CHAT_USER_DID_EDIT.negate()
},
menu: {
id: MENU_INLINE_CHAT_WIDGET,
@ -521,7 +531,7 @@ export class CloseAction extends AbstractInlineChatAction {
}
async runInlineChatCommand(_accessor: ServicesAccessor, ctrl: InlineChatController, _editor: ICodeEditor, ..._args: any[]): Promise<void> {
ctrl.finishExistingSession();
ctrl.cancelSession();
}
}

View file

@ -10,7 +10,6 @@ import { IDimension } from 'vs/editor/common/core/dimension';
import { Emitter, Event } from 'vs/base/common/event';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { clamp } from 'vs/base/common/numbers';
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { inlineChatBackground } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
@ -22,6 +21,7 @@ import { ChatModel } from 'vs/workbench/contrib/chat/common/chatModel';
import { Range } from 'vs/editor/common/core/range';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { EditorOption } from 'vs/editor/common/config/editorOptions';
export class InlineChatContentWidget implements IContentWidget {
@ -64,6 +64,7 @@ export class InlineChatContentWidget implements IContentWidget {
ChatAgentLocation.Editor,
{ resource: true },
{
defaultElementHeight: 32,
editorOverflowWidgetsDomNode: _editor.getOverflowWidgetsDomNode(),
renderStyle: 'compact',
renderInputOnTop: true,
@ -123,20 +124,16 @@ export class InlineChatContentWidget implements IContentWidget {
}
return {
position: this._position,
preference: [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW]
preference: [ContentWidgetPositionPreference.BELOW]
};
}
beforeRender(): IDimension | null {
const contentWidth = this._editor.getLayoutInfo().contentWidth;
const minWidth = Math.round(contentWidth * 0.38);
const maxWidth = Math.round(contentWidth * 0.82);
const width = clamp(220, minWidth, maxWidth);
const maxHeight = this._widget.input.inputEditor.getOption(EditorOption.lineHeight) * 5;
const inputEditorHeight = this._widget.inputEditor.getContentHeight();
this._widget.inputEditor.layout(new dom.Dimension(width, inputEditorHeight));
this._widget.inputEditor.layout(new dom.Dimension(360, Math.min(maxHeight, inputEditorHeight)));
// const actualHeight = this._widget.inputPartHeight;
// return new dom.Dimension(width, actualHeight);

View file

@ -934,7 +934,13 @@ export class InlineChatController implements IEditorContribution {
this._zone.value.updatePositionAndHeight(widgetPosition);
} else if (initialRender) {
widgetPosition = this._editor.getSelection().getStartPosition();
const selection = this._editor.getSelection();
widgetPosition = selection.getEndPosition();
if (Range.spansMultipleLines(selection) && widgetPosition.column === 1) {
// selection ends on "nothing" -> move up to match the
// rendered/visible part of the selection
widgetPosition = this._editor.getModel().validatePosition(widgetPosition.delta(-1, Number.MAX_SAFE_INTEGER));
}
this._input.value.show(widgetPosition);
} else {

View file

@ -453,7 +453,7 @@ export class LiveStrategy extends EditModeStrategy {
data.viewZoneId = undefined;
}
});
this._ctxCurrentChangeShowsDiff.set(typeof data?.viewZoneId === 'number');
this._ctxCurrentChangeShowsDiff.set(typeof data?.viewZoneId === 'string');
scrollState.restore(this._editor);
};

View file

@ -189,10 +189,11 @@ export class InlineChatWidget {
location,
{ resource: true },
{
// TODO@jrieken support editable code blocks
defaultElementHeight: 32,
renderStyle: 'compact',
renderInputOnTop: true,
supportsFileReferences: true,
editorOverflowWidgetsDomNode: options.editorOverflowWidgetsDomNode,
editableCodeBlocks: options.editableCodeBlocks,
menus: {
executeToolbar: options.inputMenuId,
@ -259,6 +260,9 @@ export class InlineChatWidget {
this._onDidChangeHeight.fire();
}));
this._store.add(this.chatWidget.onDidChangeContentHeight(() => {
this._onDidChangeHeight.fire();
}));
// context keys
this._ctxResponseFocused = CTX_INLINE_CHAT_RESPONSE_FOCUSED.bindTo(this._contextKeyService);
@ -267,8 +271,8 @@ export class InlineChatWidget {
this._store.add(tracker.onDidFocus(() => this._ctxResponseFocused.set(true)));
this._ctxInputEditorFocused = CTX_INLINE_CHAT_FOCUSED.bindTo(_contextKeyService);
this._chatWidget.inputEditor.onDidFocusEditorWidget(() => this._ctxInputEditorFocused.set(true));
this._chatWidget.inputEditor.onDidBlurEditorWidget(() => this._ctxInputEditorFocused.set(false));
this._store.add(this._chatWidget.inputEditor.onDidFocusEditorWidget(() => this._ctxInputEditorFocused.set(true)));
this._store.add(this._chatWidget.inputEditor.onDidBlurEditorWidget(() => this._ctxInputEditorFocused.set(false)));
const statusMenuId = options.statusMenuId instanceof MenuId ? options.statusMenuId : options.statusMenuId.menu;
const statusMenuOptions = options.statusMenuId instanceof MenuId ? undefined : options.statusMenuId.options;

View file

@ -14,7 +14,7 @@ import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget';
import { localize } from 'vs/nls';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, ACTION_VIEW_IN_CHAT, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_FEEDBACK, MENU_INLINE_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { ACTION_ACCEPT_CHANGES, ACTION_REGENERATE_RESPONSE, ACTION_TOGGLE_DIFF, ACTION_VIEW_IN_CHAT, CTX_INLINE_CHAT_OUTER_CURSOR_POSITION, MENU_INLINE_CHAT_WIDGET, MENU_INLINE_CHAT_WIDGET_FEEDBACK, MENU_INLINE_CHAT_WIDGET_STATUS } from 'vs/workbench/contrib/inlineChat/common/inlineChat';
import { EditorBasedInlineChatWidget } from './inlineChatWidget';
import { MenuId } from 'vs/platform/actions/common/actions';
@ -49,7 +49,7 @@ export class InlineChatZoneWidget extends ZoneWidget {
menu: MENU_INLINE_CHAT_WIDGET_STATUS,
options: {
buttonConfigProvider: action => {
if (action.id === ACTION_REGENERATE_RESPONSE) {
if (action.id === ACTION_REGENERATE_RESPONSE || action.id === ACTION_TOGGLE_DIFF) {
return { showIcon: true, showLabel: false, isSecondary: true };
} else if (action.id === ACTION_VIEW_IN_CHAT || action.id === ACTION_ACCEPT_CHANGES) {
return { isSecondary: false };
@ -132,14 +132,14 @@ export class InlineChatZoneWidget extends ZoneWidget {
const marginWithoutIndentation = info.glyphMarginWidth + info.decorationsWidth + info.lineNumbersWidth;
this.container.style.marginLeft = `${marginWithoutIndentation}px`;
this._setWidgetMargins(position);
super.show(position, this._computeHeightInLines());
this._setWidgetMargins(position);
this.widget.focus();
}
override updatePositionAndHeight(position: Position): void {
this._setWidgetMargins(position);
super.updatePositionAndHeight(position, this._computeHeightInLines());
this._setWidgetMargins(position);
}
protected override _getWidth(info: EditorLayoutInfo): number {
@ -157,12 +157,17 @@ export class InlineChatZoneWidget extends ZoneWidget {
if (!viewModel) {
return 0;
}
const visibleRange = viewModel.getCompletelyVisibleViewRange();
const startLineVisibleRange = visibleRange.startLineNumber;
const positionLine = position.lineNumber;
let indentationLineNumber: number | undefined;
let indentationLevel: number | undefined;
for (let lineNumber = positionLine; lineNumber >= startLineVisibleRange; lineNumber--) {
if (!visibleRange.containsPosition(position)) {
// this is needed because `getOffsetForColumn` won't work when the position
// isn't visible/rendered
return 0;
}
let indentationLevel = viewModel.getLineFirstNonWhitespaceColumn(position.lineNumber);
let indentationLineNumber = position.lineNumber;
for (let lineNumber = position.lineNumber; lineNumber >= visibleRange.startLineNumber; lineNumber--) {
const currentIndentationLevel = viewModel.getLineFirstNonWhitespaceColumn(lineNumber);
if (currentIndentationLevel !== 0) {
indentationLineNumber = lineNumber;
@ -170,7 +175,8 @@ export class InlineChatZoneWidget extends ZoneWidget {
break;
}
}
return this.editor.getOffsetForColumn(indentationLineNumber ?? positionLine, indentationLevel ?? viewModel.getLineFirstNonWhitespaceColumn(positionLine));
return Math.max(0, this.editor.getOffsetForColumn(indentationLineNumber, indentationLevel)); // double-guard against invalie getOffsetForColumn-calls
}
private _setWidgetMargins(position: Position): void {

View file

@ -50,12 +50,12 @@
/* status */
.monaco-workbench .inline-chat .status {
padding-top: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
.monaco-workbench .inline-chat .status .actions.hidden {
display: none;
}
@ -64,7 +64,7 @@
overflow: hidden;
color: var(--vscode-descriptionForeground);
font-size: 11px;
align-self: baseline;
padding-top: 4px;
padding-left: 10px;
display: inline-flex;
}
@ -130,6 +130,7 @@
.monaco-workbench .inline-chat .status .actions {
display: flex;
padding-top: 4px;
}
.monaco-workbench .inline-chat .status .actions > .monaco-button,
@ -234,9 +235,9 @@
background-color: var(--vscode-inlineChat-regionHighlight);
}
.monaco-workbench .inline-chat-slash-command {
.monaco-workbench .interactive-session .interactive-input-and-execute-toolbar .monaco-editor .inline-chat-slash-command {
background-color: var(--vscode-chat-slashCommandBackground);
color: var(--vscode-chat-slashCommandForeground);
color: var(--vscode-chat-slashCommandForeground); /* Overrides the foreground color rule in chat.css */
border-radius: 4px;
padding: 1px;
}

View file

@ -15,6 +15,10 @@
display: none;
}
.monaco-workbench .inline-chat-content-widget.interactive-session .interactive-session {
max-width: unset;
}
.monaco-workbench .inline-chat-content-widget.interactive-session .interactive-input-part .interactive-execute-toolbar {
margin-bottom: 1px;
}

View file

@ -176,6 +176,7 @@ export const CTX_INLINE_CHAT_EDIT_MODE = new RawContextKey<EditMode>('config.inl
export const ACTION_ACCEPT_CHANGES = 'inlineChat.acceptChanges';
export const ACTION_REGENERATE_RESPONSE = 'inlineChat.regenerate';
export const ACTION_VIEW_IN_CHAT = 'inlineChat.viewInChat';
export const ACTION_TOGGLE_DIFF = 'inlineChat.toggleDiff';
// --- menus

View file

@ -253,7 +253,7 @@ class InteractiveWindowWorkingCopyEditorHandler extends Disposable implements IW
}
}
registerWorkbenchContribution2(InteractiveDocumentContribution.ID, InteractiveDocumentContribution, WorkbenchPhase.AfterRestored);
registerWorkbenchContribution2(InteractiveDocumentContribution.ID, InteractiveDocumentContribution, WorkbenchPhase.BlockRestore);
registerWorkbenchContribution2(InteractiveInputContentProvider.ID, InteractiveInputContentProvider, {
editorTypeId: INTERACTIVE_WINDOW_EDITOR_ID
});

View file

@ -324,7 +324,7 @@ class LanguageStatus {
href: URI.from({
scheme: 'command', path: command.id, query: command.arguments && JSON.stringify(command.arguments)
}).toString()
}, undefined, this._openerService));
}, { hoverDelegate: nativeHoverDelegate }, this._openerService));
}
// -- pin

View file

@ -316,8 +316,8 @@ export class NotebookChatController extends Disposable implements INotebookEdito
run(index: number, input: string | undefined, autoSend: boolean | undefined): void {
if (this._widget) {
if (this._widget.afterModelPosition !== index) {
this._disposeWidget();
const window = getWindow(this._widget.domNode);
this._disposeWidget();
scheduleAtNextAnimationFrame(window, () => {
this._createWidget(index, input, autoSend, undefined);

View file

@ -929,7 +929,7 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
// wait for the editor to be created if the cell is in editing mode
cell.getEditState() === CellEditState.Editing
// wait for the editor to be created if we are revealing the first line of the cell
|| revealType === CellRevealType.FirstLineIfOutsideViewport
|| (revealType === CellRevealType.FirstLineIfOutsideViewport && cell.cellKind === CellKind.Code)
) && !cell.editorAttached) {
return getEditorAttachedPromise(cell);
}

View file

@ -561,7 +561,7 @@ async function webviewPreloads(ctx: PreloadContext) {
let lastTimeScrolled: number | undefined;
function flagRecentlyScrolled(node: Element, deltaY?: number) {
scrolledElement = node;
if (!deltaY) {
if (deltaY === undefined) {
lastTimeScrolled = Date.now();
previousDelta = undefined;
node.setAttribute('recentlyScrolled', 'true');

View file

@ -97,7 +97,7 @@ export class SyncScroll extends Disposable implements IWorkbenchContribution {
}
if (!isEditorPaneWithScrolling(pane)) {
return;
continue;
}
const initialOffset = this.paneInitialScrollTop.get(pane);
@ -105,10 +105,17 @@ export class SyncScroll extends Disposable implements IWorkbenchContribution {
throw new Error('Could not find initial offset for pane');
}
pane.setScrollPosition({
const currentPanePosition = pane.getScrollPosition();
const newPaneScrollPosition = {
scrollTop: initialOffset.scrollTop + scrolledFromInitial.scrollTop,
scrollLeft: initialOffset.scrollLeft !== undefined && scrolledFromInitial.scrollLeft !== undefined ? initialOffset.scrollLeft + scrolledFromInitial.scrollLeft : undefined,
});
};
if (currentPanePosition.scrollTop === newPaneScrollPosition.scrollTop && currentPanePosition.scrollLeft === newPaneScrollPosition.scrollLeft) {
continue;
}
pane.setScrollPosition(newPaneScrollPosition);
}
}

View file

@ -147,6 +147,7 @@ export class SpeechService extends Disposable implements ISpeechService {
const sessionStart = Date.now();
let sessionRecognized = false;
let sessionContentLength = 0;
const disposables = new DisposableStore();
@ -163,16 +164,22 @@ export class SpeechService extends Disposable implements ISpeechService {
context: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Context of the session.' };
sessionDuration: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Duration of the session.' };
sessionRecognized: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'If speech was recognized.' };
sessionContentLength: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'Length of the recognized text.' };
sessionLanguage: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Configured language for the session.' };
};
type SpeechToTextSessionEvent = {
context: string;
sessionDuration: number;
sessionRecognized: boolean;
sessionContentLength: number;
sessionLanguage: string;
};
this.telemetryService.publicLog2<SpeechToTextSessionEvent, SpeechToTextSessionClassification>('speechToTextSession', {
context,
sessionDuration: Date.now() - sessionStart,
sessionRecognized
sessionRecognized,
sessionContentLength,
sessionLanguage: language
});
}
@ -194,9 +201,13 @@ export class SpeechService extends Disposable implements ISpeechService {
}
break;
case SpeechToTextStatus.Recognizing:
case SpeechToTextStatus.Recognized:
sessionRecognized = true;
break;
case SpeechToTextStatus.Recognized:
if (typeof e.text === 'string') {
sessionContentLength += e.text.length;
}
break;
case SpeechToTextStatus.Stopped:
onSessionStoppedOrCanceled();
break;

View file

@ -139,12 +139,6 @@ export class TerminalProfileQuickpick {
if (context.item.profile.env) {
newConfigValue[name].env = context.item.profile.env;
}
if (context.item.profile.color) {
newConfigValue[name].color = context.item.profile.color;
}
if (context.item.profile.icon) {
newConfigValue[name].icon = context.item.profile.icon;
}
await this._configurationService.updateValue(profilesKey, newConfigValue, ConfigurationTarget.USER);
},
onKeyMods: mods => keyMods = mods

View file

@ -259,21 +259,36 @@ export async function showRunRecentQuickPick(
}
});
let terminalScrollStateSaved = false;
function restoreScrollState() {
terminalScrollStateSaved = false;
instance.xterm?.markTracker.restoreScrollState();
instance.xterm?.markTracker.clear();
}
quickPick.onDidChangeActive(async () => {
const xterm = instance.xterm;
if (!xterm) {
return;
}
const [item] = quickPick.activeItems;
if ('command' in item && item.command) {
if ('command' in item && item.command && item.command.marker) {
if (!terminalScrollStateSaved) {
xterm.markTracker.saveScrollState();
terminalScrollStateSaved = true;
}
xterm.markTracker.revealCommand(item.command);
const promptRowCount = item.command.getPromptRowCount();
const commandRowCount = item.command.getCommandRowCount();
xterm.markTracker.revealRange({
start: {
x: 1,
y: item.command.marker.line - (promptRowCount - 1) + 1
},
end: {
x: instance.cols,
y: item.command.marker.line + (commandRowCount - 1) + 1
}
});
} else {
terminalScrollStateSaved = false;
xterm.markTracker.restoreScrollState();
restoreScrollState();
}
});
quickPick.onDidAccept(async () => {
@ -289,13 +304,9 @@ export async function showRunRecentQuickPick(
if (quickPick.keyMods.alt) {
instance.focus();
}
terminalScrollStateSaved = false;
instance.xterm?.markTracker.restoreScrollState();
});
quickPick.onDidHide(() => {
terminalScrollStateSaved = false;
instance.xterm?.markTracker.restoreScrollState();
restoreScrollState();
});
quickPick.onDidHide(() => restoreScrollState());
if (value) {
quickPick.value = value;
}

View file

@ -89,7 +89,7 @@ export class TerminalVoiceSession extends Disposable {
}, voiceTimeout));
this._cancellationTokenSource = new CancellationTokenSource();
this._register(toDisposable(() => this._cancellationTokenSource?.dispose(true)));
const session = await this._speechService.createSpeechToTextSession(this._cancellationTokenSource?.token);
const session = await this._speechService.createSpeechToTextSession(this._cancellationTokenSource?.token, 'terminal');
this._disposables.add(session.onDidChange((e) => {
if (this._cancellationTokenSource?.token.isCancellationRequested) {

View file

@ -277,8 +277,10 @@ export class TerminalChatController extends Disposable implements ITerminalContr
return;
}
if (progress.kind === 'content' || progress.kind === 'markdownContent') {
if (progress.kind === 'content') {
responseContent += progress.content;
} else if (progress.kind === 'markdownContent') {
responseContent += progress.content.value;
}
if (this._currentRequest) {
model.acceptResponseProgress(this._currentRequest, progress);

View file

@ -221,12 +221,10 @@ export class TerminalLinkQuickpick extends DisposableStore {
}
// Skip the link if it's a duplicate URI + line/col
if (description) {
if (linkUriKeys.has(label + '|' + description)) {
continue;
}
linkUriKeys.add(label + '|' + description);
if (linkUriKeys.has(label + '|' + (description ?? ''))) {
continue;
}
linkUriKeys.add(label + '|' + (description ?? ''));
}
picks.push({ label, link, description });

View file

@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import * as dom from 'vs/base/browser/dom';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ITerminalContribution, ITerminalInstance, IXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal';
import { registerTerminalContribution } from 'vs/workbench/contrib/terminal/browser/terminalExtensions';
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager';
import { SuggestAddon } from 'vs/workbench/contrib/terminalContrib/suggest/browser/terminalSuggestAddon';
import { ITerminalProcessManager, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal';
import { ITerminalConfiguration, ITerminalProcessManager, TERMINAL_CONFIG_SECTION, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal';
import type { Terminal as RawXtermTerminal } from '@xterm/xterm';
import { ContextKeyExpr, IContextKey, IContextKeyService, IReadableSet } from 'vs/platform/contextkey/common/contextkey';
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
@ -18,6 +18,8 @@ import { registerActiveInstanceAction } from 'vs/workbench/contrib/terminal/brow
import { localize2 } from 'vs/nls';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { KeyCode } from 'vs/base/common/keyCodes';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TerminalSettingId } from 'vs/platform/terminal/common/terminal';
class TerminalSuggestContribution extends DisposableStore implements ITerminalContribution {
static readonly ID = 'terminal.suggest';
@ -26,17 +28,18 @@ class TerminalSuggestContribution extends DisposableStore implements ITerminalCo
return instance.getContribution<TerminalSuggestContribution>(TerminalSuggestContribution.ID);
}
private _addon: SuggestAddon | undefined;
private _addon: MutableDisposable<SuggestAddon> = new MutableDisposable();
private _terminalSuggestWidgetContextKeys: IReadableSet<string> = new Set(TerminalContextKeys.suggestWidgetVisible.key);
private _terminalSuggestWidgetVisibleContextKey: IContextKey<boolean>;
get addon(): SuggestAddon | undefined { return this._addon; }
get addon(): SuggestAddon | undefined { return this._addon.value; }
constructor(
private readonly _instance: ITerminalInstance,
_processManager: ITerminalProcessManager,
widgetManager: TerminalWidgetManager,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IInstantiationService private readonly _instantiationService: IInstantiationService
) {
super();
@ -51,21 +54,31 @@ class TerminalSuggestContribution extends DisposableStore implements ITerminalCo
this._loadSuggestAddon(xterm.raw);
}
}));
this.add(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(TerminalSettingId.SendKeybindingsToShell)) {
this._loadSuggestAddon(xterm.raw);
}
}));
}
private _loadSuggestAddon(xterm: RawXtermTerminal): void {
const sendingKeybindingsToShell = this._configurationService.getValue<ITerminalConfiguration>(TERMINAL_CONFIG_SECTION).sendKeybindingsToShell;
if (sendingKeybindingsToShell) {
this._addon.dispose();
return;
}
if (this._terminalSuggestWidgetVisibleContextKey) {
this._addon = this._instantiationService.createInstance(SuggestAddon, this._terminalSuggestWidgetVisibleContextKey);
xterm.loadAddon(this._addon);
this._addon?.setPanel(dom.findParentWithClass(xterm.element!, 'panel')!);
this._addon?.setScreen(xterm.element!.querySelector('.xterm-screen')!);
this.add(this._instance.onDidBlur(() => this._addon?.hideSuggestWidget()));
this.add(this._addon.onAcceptedCompletion(async text => {
this._addon.value = this._instantiationService.createInstance(SuggestAddon, this._terminalSuggestWidgetVisibleContextKey);
xterm.loadAddon(this._addon.value);
this._addon.value.setPanel(dom.findParentWithClass(xterm.element!, 'panel')!);
this._addon.value.setScreen(xterm.element!.querySelector('.xterm-screen')!);
this.add(this._instance.onDidBlur(() => this._addon.value?.hideSuggestWidget()));
this.add(this._addon.value.onAcceptedCompletion(async text => {
this._instance.focus();
this._instance.sendText(text, false);
}));
this.add(this._instance.onDidSendText((text) => {
this._addon?.handleNonXtermData(text);
this._addon.value?.handleNonXtermData(text);
}));
}
}

View file

@ -513,7 +513,7 @@ export class WebviewElement extends Disposable implements IWebview, WebviewFindD
this.element?.classList.add('ready');
if (this._state.type === WebviewState.Type.Initializing) {
this._state.pendingMessages.forEach(({ channel, data }) => this.doPostMessage(channel, data));
this._state.pendingMessages.forEach(({ channel, data, resolve }) => resolve(this.doPostMessage(channel, data)));
}
this._state = WebviewState.Ready;

View file

@ -853,17 +853,21 @@ export class GettingStartedPage extends EditorPane {
if (gettingStartedList.itemCount) {
this.container.classList.remove('noWalkthroughs');
if (videoList?.itemCount > 0) {
this.container.classList.remove('noVideos');
reset(rightColumn, videoList?.getDomElement(), gettingStartedList.getDomElement());
} else {
this.container.classList.add('noVideos');
reset(rightColumn, gettingStartedList.getDomElement());
}
}
else {
this.container.classList.add('noWalkthroughs');
if (videoList?.itemCount > 0) {
this.container.classList.remove('noVideos');
reset(rightColumn, videoList?.getDomElement());
}
else {
this.container.classList.add('noVideos');
reset(rightColumn);
}
}
@ -872,7 +876,7 @@ export class GettingStartedPage extends EditorPane {
};
const layoutRecentList = () => {
if (this.container.classList.contains('noWalkthroughs') && videoList?.itemCount === 0) {
if (this.container.classList.contains('noWalkthroughs') && this.container.classList.contains('noVideos')) {
recentList.setLimit(10);
reset(leftColumn, startList.getDomElement());
reset(rightColumn, recentList.getDomElement());

View file

@ -74,12 +74,17 @@ export class CustomEditorLabelService extends Disposable implements ICustomEdito
this.enabled = this.configurationService.getValue<boolean>(CustomEditorLabelService.SETTING_ID_ENABLED);
}
private _templateRegexValidation: RegExp = /[a-zA-Z0-9]/;
private storeCustomPatterns(): void {
this.patterns = [];
const customLabelPatterns = this.configurationService.getValue<ICustomEditorLabelObject>(CustomEditorLabelService.SETTING_ID_PATTERNS);
for (const pattern in customLabelPatterns) {
const template = customLabelPatterns[pattern];
if (!this._templateRegexValidation.test(template)) {
continue;
}
const isAbsolutePath = isAbsolute(pattern);
const parsedPattern = parseGlob(pattern);

View file

@ -84,10 +84,6 @@ declare module 'vscode' {
/**
* Execute a command, sending ^C as necessary to interrupt any running command if needed.
*
* *Note* This is not guaranteed to work as [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration)
* must be activated. Check whether {@link TerminalShellExecution.exitCode} is rejected to
* verify whether it was successful.
*
* @param commandLine The command line to execute, this is the exact text that will be sent
* to the terminal.
*

View file

@ -3563,10 +3563,10 @@ electron-to-chromium@^1.4.648:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.648.tgz#c7b46c9010752c37bb4322739d6d2dd82354fbe4"
integrity sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg==
electron@28.2.6:
version "28.2.6"
resolved "https://registry.yarnpkg.com/electron/-/electron-28.2.6.tgz#ec4958ff759009e3eb2c9489df5eb02f989f06bf"
integrity sha512-RuhbW+ifvh3DqnVlHCcCKhKIFOxTktq1GN1gkIkEZ8y5LEZfcjOkxB2s6Fd1S6MzsMZbiJti+ZJG5hXS4SDVLQ==
electron@28.2.8:
version "28.2.8"
resolved "https://registry.yarnpkg.com/electron/-/electron-28.2.8.tgz#b83d70ca00c0e767f0125fcec85f39aafe39ee4c"
integrity sha512-VgXw2OHqPJkobIC7X9eWh3atptjnELaP+zlbF9Oz00ridlaOWmtLPsp6OaXbLw35URpMr0iYesq8okKp7S0k+g==
dependencies:
"@electron/get" "^2.0.0"
"@types/node" "^18.11.18"
@ -3694,21 +3694,22 @@ es-to-primitive@^1.2.1:
is-date-object "^1.0.1"
is-symbol "^1.0.2"
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
version "0.10.53"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1"
integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==
es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@^0.10.62, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46:
version "0.10.63"
resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.63.tgz#9c222a63b6a332ac80b1e373b426af723b895bd6"
integrity sha512-hUCZd2Byj/mNKjfP9jXrdVZ62B8KuA/VoK7X8nUh5qT+AxDmcbvZz041oDVZdbIN1qW6XY9VDNwzkvKnZvK2TQ==
dependencies:
es6-iterator "~2.0.3"
es6-symbol "~3.1.3"
next-tick "~1.0.0"
es6-iterator "^2.0.3"
es6-symbol "^3.1.3"
esniff "^2.0.1"
next-tick "^1.1.0"
es6-error@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.3:
es6-iterator@^2.0.1, es6-iterator@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
@ -3717,7 +3718,7 @@ es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.3:
es5-ext "^0.10.35"
es6-symbol "^3.1.1"
es6-symbol@^3.1.1, es6-symbol@~3.1.3:
es6-symbol@^3.1.1, es6-symbol@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18"
integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==
@ -3909,6 +3910,16 @@ eslint@^5.0.1:
table "^5.2.3"
text-table "^0.2.0"
esniff@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/esniff/-/esniff-2.0.1.tgz#a4d4b43a5c71c7ec51c51098c1d8a29081f9b308"
integrity sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==
dependencies:
d "^1.0.1"
es5-ext "^0.10.62"
event-emitter "^0.3.5"
type "^2.7.2"
espree@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a"
@ -6862,11 +6873,6 @@ next-tick@1, next-tick@^1.1.0:
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb"
integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==
next-tick@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
@ -9620,6 +9626,11 @@ type@^2.0.0:
resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f"
integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==
type@^2.7.2:
version "2.7.2"
resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0"
integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==
typedarray@^0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"