From 913c0606d03befc4f025d325a53df22be9df8221 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 19 Nov 2020 04:02:54 -0500 Subject: [PATCH] Refines rebase editor Adds button to rebase editor to toggle it on/off Adds commands to toggle rebase editor on/off Adds settings UI to toggle rebase editor on/off --- package.json | 22 +++- src/commands.ts | 1 + src/commands/common.ts | 2 + src/commands/rebaseEditor.ts | 25 +++++ src/configuration.ts | 10 +- src/container.ts | 11 +- .../apps/images/settings/rebase-editor.png | Bin 0 -> 45997 bytes src/webviews/apps/rebase/rebase.html | 7 +- src/webviews/apps/rebase/rebase.ts | 12 +++ src/webviews/apps/scss/buttons.scss | 61 +++++++++++ src/webviews/apps/scss/rebase.scss | 18 +++- .../apps/settings/partials/rebase-editor.html | 39 +++++++ src/webviews/apps/settings/settings.html | 12 +++ src/webviews/apps/shared/appWithConfigBase.ts | 17 ++- src/webviews/apps/shared/theme.ts | 4 + src/webviews/protocol.ts | 16 +-- src/webviews/rebaseEditor.ts | 114 ++++++++++++++++++--- src/webviews/settingsWebview.ts | 1 + src/webviews/webviewBase.ts | 71 ++++++++++++- 19 files changed, 407 insertions(+), 36 deletions(-) create mode 100644 src/commands/rebaseEditor.ts create mode 100644 src/webviews/apps/images/settings/rebase-editor.png create mode 100644 src/webviews/apps/settings/partials/rebase-editor.html diff --git a/package.json b/package.json index 9478b9e..235e694 100644 --- a/package.json +++ b/package.json @@ -104,6 +104,8 @@ "onCommand:gitlens.diffWithWorkingInDiffLeft", "onCommand:gitlens.diffWithWorkingInDiffRight", "onCommand:gitlens.diffLineWithWorking", + "onCommand:gitlens.disableRebaseEditor", + "onCommand:gitlens.enableRebaseEditor", "onCommand:gitlens.toggleFileBlame", "onCommand:gitlens.toggleFileBlameInDiffLeft", "onCommand:gitlens.toggleFileBlameInDiffRight", @@ -2759,6 +2761,16 @@ "category": "GitLens" }, { + "command": "gitlens.disableRebaseEditor", + "title": "Disable Interactive Rebase Editor", + "category": "GitLens" + }, + { + "command": "gitlens.enableRebaseEditor", + "title": "Enable Interactive Rebase Editor", + "category": "GitLens" + }, + { "command": "gitlens.toggleFileBlame", "title": "Toggle File Blame", "category": "GitLens", @@ -4527,6 +4539,14 @@ "when": "gitlens:activeFileStatus =~ /blameable/" }, { + "command": "gitlens.disableRebaseEditor", + "when": "gitlens:enabled" + }, + { + "command": "gitlens.enableRebaseEditor", + "when": "gitlens:enabled" + }, + { "command": "gitlens.externalDiff", "when": "gitlens:activeFileStatus =~ /tracked/" }, @@ -7919,7 +7939,7 @@ "customEditors": [ { "viewType": "gitlens.rebase", - "displayName": "Interactive Rebase Editor", + "displayName": "GitLens Interactive Rebase Editor", "selector": [ { "filenamePattern": "git-rebase-todo" diff --git a/src/commands.ts b/src/commands.ts index e6a4d93..fc74411 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -34,6 +34,7 @@ export * from './commands/openPullRequestOnRemote'; export * from './commands/openRepoOnRemote'; export * from './commands/openRevisionFile'; export * from './commands/openWorkingFile'; +export * from './commands/rebaseEditor'; export * from './commands/refreshHover'; export * from './commands/remoteProviders'; export * from './commands/repositories'; diff --git a/src/commands/common.ts b/src/commands/common.ts index 90e0e30..2cdad75 100644 --- a/src/commands/common.ts +++ b/src/commands/common.ts @@ -63,6 +63,8 @@ export enum Commands { DiffWithWorkingInDiffRight = 'gitlens.diffWithWorkingInDiffRight', DiffLineWithWorking = 'gitlens.diffLineWithWorking', DisconnectRemoteProvider = 'gitlens.disconnectRemoteProvider', + DisableRebaseEditor = 'gitlens.disableRebaseEditor', + EnableRebaseEditor = 'gitlens.enableRebaseEditor', ExternalDiff = 'gitlens.externalDiff', ExternalDiffAll = 'gitlens.externalDiffAll', FetchRepositories = 'gitlens.fetchRepositories', diff --git a/src/commands/rebaseEditor.ts b/src/commands/rebaseEditor.ts new file mode 100644 index 0000000..38f83b6 --- /dev/null +++ b/src/commands/rebaseEditor.ts @@ -0,0 +1,25 @@ +'use strict'; +import { command, Command, Commands } from './common'; +import { Container } from '../container'; + +@command() +export class DisableRebaseEditorCommand extends Command { + constructor() { + super(Commands.DisableRebaseEditor); + } + + execute() { + return Container.rebaseEditor.setEnabled(false); + } +} + +@command() +export class EnableRebaseEditorCommand extends Command { + constructor() { + super(Commands.EnableRebaseEditor); + } + + execute() { + return Container.rebaseEditor.setEnabled(true); + } +} diff --git a/src/configuration.ts b/src/configuration.ts index 716937a..3abba2c 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -137,10 +137,12 @@ export class Configuration { .get(section === undefined ? extensionId : section, defaultValue)!; } + getAny(section: string, scope?: ConfigurationScope | null): T | undefined; + getAny(section: string, scope: ConfigurationScope | null | undefined, defaultValue: T): T; getAny(section: string, scope?: ConfigurationScope | null, defaultValue?: T) { return defaultValue === undefined - ? workspace.getConfiguration(undefined, scope).get(section)! - : workspace.getConfiguration(undefined, scope).get(section, defaultValue)!; + ? workspace.getConfiguration(undefined, scope).get(section) + : workspace.getConfiguration(undefined, scope).get(section, defaultValue); } changed(e: ConfigurationChangeEvent, s1: S1, scope?: ConfigurationScope | null): boolean; @@ -242,8 +244,8 @@ export class Configuration { .inspect(section === undefined ? extensionId : section); } - inspectAny(section: string, scope?: ConfigurationScope | null) { - return workspace.getConfiguration(undefined, scope).inspect(section); + inspectAny(section: string, scope?: ConfigurationScope | null) { + return workspace.getConfiguration(undefined, scope).inspect(section); } migrate( diff --git a/src/container.ts b/src/container.ts index 76fb1e9..cbbd19f 100644 --- a/src/container.ts +++ b/src/container.ts @@ -91,7 +91,7 @@ export class Container { }); } - context.subscriptions.push(new RebaseEditorProvider()); + context.subscriptions.push((this._rebaseEditor = new RebaseEditorProvider())); context.subscriptions.push(new GitTerminalLinkProvider()); context.subscriptions.push(new GitFileSystemProvider()); @@ -237,6 +237,15 @@ export class Container { return this._lineTracker; } + private static _rebaseEditor: RebaseEditorProvider | undefined; + static get rebaseEditor() { + if (this._rebaseEditor === undefined) { + this._context.subscriptions.push((this._rebaseEditor = new RebaseEditorProvider())); + } + + return this._rebaseEditor; + } + private static _remotesView: RemotesView | undefined; static get remotesView() { if (this._remotesView === undefined) { diff --git a/src/webviews/apps/images/settings/rebase-editor.png b/src/webviews/apps/images/settings/rebase-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..a8570c12c130cc6a4746068773bd069f7f0b70eb GIT binary patch literal 45997 zcmbTeWmHyQ6z&TMN+?KoNOyOGba#VvcY~B5-QA$1NOyO)bax{i(r_04d(ODyo^d{$ zaX&ba4ZN}UUTZ${_dN3rRge?^0FMI?0RizrQbI%t0s<-!0s^uT77843!(A8vUm%^7 z#DyWs#_$fnH_&E6vO*9LmC*=~1~A}zIC}|ACkP0{?$>{i{dT{MAt0)SB}If(-1Uw# z;k;CP@7kS`OGrOKqWtq-OO!Q67J)|p1*=tK`8P16CCe8nFR9(O3^DrS!XtPvTO1i(+{^AdV@O(elF2zdZ{qWCwFVii>E7JX1 zf3e1b#cYg~xE7}7xU_yXjm=7JrOD-kGFeBiPK`P8Q|I=Syny#cAm-cmSo(Pi;FXMt zRCq4`Qp`2W^4Ps;e|h@(Ir!uHMt3k0KKIoa&*|fKy!>LVmD_nQrgRlJdb-@`)E|Y9 z66pK%_X~JY&B#SA%U+kGv8tY!;Gqk z+X5aJ#!b*Vo(K8S0?(X%52xULAkfD^zn+)_==^?3Ny%v53s~{1+i~CLOSd)eJ;%lh zyM-#4>gYnq7~HBWETeqN3^+ti|$Xkgx+13zB0@te>;4rf7e3$i z3p_ua`X=wGvTg6~`heGt#Crx2UJZvz&WVS(^&MOoC1#<6^HZOj<|dcFa@qV({e-@( zGGR*82L}hz$@Dh!6$W!?oz{9s|W54iHrY`1g2(9jtKsHiLsr;7-^&c2~-WxqU{4JXl&b=Fu+F)Fc9 zOF)z~LnZ5ZQq2^qB-m_p1%eBFYGh;->4c1&NBV+HA~urAlMD?G`lfT(MP;(i>3u!^ zTi#A@vfJi^33al2J@@4W{7v+T z56AUiul6^FcPY#dIab}b>f4`6MFwAjaBWire4h;op+l0!`$va|w}gwC6Q4C?&H2Je z(eseqp?P7qGLW*mo^ICK^*f=cwllb#8hSYQa<9Z0%qoX9yLR7w+$r#Vd3J7B|Kfc; zNRhowm11WP?p*)v5l^pGk3ADJGZI`eUQXBJMVIRtb#UW4FV)$|Bwv`GgR{pWmn;>G zh@a(if57c>xD3v$j?0S69QY;ki|xVLHg|qWa}3{*Rt!94cg#z5S4O)ex9XD z41`Pury@Nm9{~y!m*4$HB z++pxYD^dJK6z+!etuW$8THMIu&UrtfcwDyoW~f1T5V$KX!G@6#<3~#QG~vWU&+B@G zH6C7lMclkHMzT&VslfjW6UpKFaE8b2gxBkq(FOCXu(0snSmxika)t>7A@AWE1t|Zo zBJpj`X<$n!0E?-wQSeWNzQ_>FQ=LCoih>F}Eg6z(7COau^!E(TEI3J@0yu~xtsVOa zBoHK|tfHACow=qMIKC2b#8s1<9YxlLvix;OXSYGbR#_ z@8cGs+tIwkjH-HSoLadaUjj<0uqo-NvOHh!k$~g2grwh?gV#yp-sIF2Tnu{gH|Cif z&1%z;3bfDs@>>$Np`oEZWhsQepbj6ReIMT-F>r8TBAgJ#jpRj)N#g9!S8h>cd-*RS zuYv^yb{5!{m*6?=k*`gn9OiWB@p}aeZj8GqqTkC9Bn!uLqG{)86 zL<`~d_vzs#9?1X=U;bR)_db3biPMYoJm4J?|IM-!nRkqWX<5#~&GC{r>p;KMrQ^oy z0+gydAe&F|5v0SFuM{xoV(i#B;!DuKF6nKr#3KFxi6<&9a z7~zRc!Gloy$MtLM#OQvhX>!Aiv2nqq<1zYbF(|8G!!vx(MXQm@6d|!-K!$^fNg>{S z;Ey_h7geg{MjR%0y3 z&D8oCxRH?@j~6;puQ|E7am>0xRQTORZ=-HqM|y*(i2cvzzWCaBV~6^-xSt!Q+QX3R z=%6~w{i2V;U*#f>kscPtIc^|;eYt`fZd$7uA=C|ti32HBKt(nta=qhy; zmFZ%21`;3g7&5Q5gQ-G7F30UJFZan<0bV8Um1|y?kzXLqWzwc;*{v`qB{YZ#uc9AK zl$#R7$1Owud4X~e(SWp=f$?MS4^&Xmk%Aw`npb>ZPrC2Tid!se1STloH*3D*B0>5; zMt6s!ED?qMdDC%GW>Out`nls@14v$k)Q}Z1X0V{E# zkXmIjaXc)S;p6?^@(0}|P^t2zlf%w4-Bvfu@7tWY;50gMH7gARk+~4;abA+)hm60= zbsN6?Te9O2pj)l8NpIBF7Fw*g%g)SfwO!#R@ks+$YEn0i-DU_{oK--8&`w@1H7`G( z&30L%i?mz4PqQ<*%2M#m*wi!(!6Yz0G~3rAaJ7$CESP1p@F#?LGy&W2TldJ$0cuP~ zo`qu(Msw_mv5U@HRB{=8D$7G`dRi@-zsqW+T1?EEkONfly3MXk|D@)A-`?I*WVs7> z+1BF<+^)Sm-+&5cS?3iK%|<~{=#HbGKT{x!o0i;#RgkT$p@D^pstgwLG&s%jOi;G} z7%>%Yrl+SJ%U%2)s@e=ZK1J~;uvyBk_k^OB5as6N^w2Y+R?7U`mf)PY{yWF=8Eo#l z7Y!DC4iy@asbXp_ET$v+-0>?=C=%qi7{u)$%$ggy%v-VAf;?!Q1jy7!r=n%F8%9(_UifWs;njZLAS zLR(?UB-}O<`Dc9N0%*W3$tlEv&zamVyadr1Im66-)Wldi!!5I=+8mD(&ItK?oi?j2 zninEy6D)m&r2pQS&B4O>8w7lg@Rh&QO#Oh(O#10l=i)lLS4l$!DGM>b0)NuKOdhv_ z5mp{U>!b>>j!HhQtw~P9t5*1UVxXjW1|i}PDFxM;;1eeE**Kn-+C(uzmAfw@Rn zk*n$&iwtvnU*On8e~qqrG4&qxxBbPoB$ucfUTLZ{RJER&7jfRt&I$A)p1CTNe5!%$ zYK|3WRI2;~KLj`umT}(8_lj~Zhtq>433*H#j^AxSz0?s+C}=+K!~Np1gFaa5PNS$l zSs{_hW;Kh=a1+ouKq?p%!lXF)M}4W*%527{y(?YAL`mzQdYnK0r!324oz8%AU#iFB zd4DMaY(z~uNB9(DnP$}=XB|-$DO*F;r|R!4c8AQPOg|Gg(SkDQwCfnd(Svu=8)0FC z8lCoDTLm%F{kGorwlY$9c=-J`u~6SA7X--QL0HX( z>@xmICL>cbSk0D5%E%-ncmCoh>2cmAA|WxF%###z@EuE_QjQSG7amN_Qt&R&7f5a* zj!xWZxpSIHxFdYIeHS@0EtVxCHUhw1p@UIobarA2hR8;@o8b&l&n-Nb6p$#4ouSqVaI9}L zJ5Zr=h~-9FV6(WSH$xrW1~aZRitb6*8>KBU>2)ZHDcIt=>{Ye2(y*Skza>H&l2>yT z+W!{$1^OY=6Ia7Re@LEoFRW-*s2pkekIkVfowUD~Gqa3Vr1FDPuHkn>jm^xqc2NDm zTH)s4m}~jYjE1R&it*9dP;H3TkLXlkbhbd&{UlCXveY;~Vfb^n3sP$Oq?8ilkB9Sh z(h(@A%-zO6<(^mjodF#K*1PI|<0^hXFLb9~--4Z|;{}V?y#l%181casaYt0Y*C5UP z{-DsVaR);U9n=c}xkQH?NByhaot=$oobxJ1%W29cA{wcrd3pXj(#yr554a`tRCd{9lo38tvv$>8!I{O>BS~L1OjG*RpWm;?LK@4 zOgRNl_t&VgZ&51hKEA^&)SQH!o!tB@;kj^}=O2>fE*IAU|D4K3(^&gUg3*cTnynT? zk=0}-@0JH~=#*n(m?Xv%=2AqW+na2JJD|4KBXq$TQmDQmNgP{&oXYP@u@VH8YKPiI zZo+VQwNXE!nhK_lJ!Ebi<&Ht*rkjUgN^V1sHD8hguZhR9;7d;z3DJiYJ?FGO1HPev z7-|3SY|fhX6jqRCvs=;p_aRZ7K=S`~h*gBaYnW_LrKWjLozx*JDq3>%UU|n)pK*1l zo}BNrN`HSe4YdfQw6fa+-wPOhw}xp z>3m=Rt^Zl)t{|tJDv)zfU^b2$j3QCy!XM#O#0xu7qG)5yNe#7)34k6r7VUWaN-?9J8<0huhg}jQMXaZ7J*@|s_Q~FQ;4B7hVM`RW5c(1<(fm!OF ze%bi3ewOz3m_X``!4xM!wZTya;)2O;HpqFRmuG$|Tf zCSAEjx4f(EzAprPp6mU-pcS;c>oB5umefzxzsPy?1?NH(2A9K@7EyMmGctwv-K~#2 z0_4I+dPLh8bQVlBq|)G}+c`Jb}5kM%|5y78IP zE}Nl^CpkWaeaAv3>}5f6H`ozE80HVQ-bh1Zpsq!1Q!#1H$Qn$Dddu=wbFUQ?bjW)9 zl0ORD7P>L$?L{4%tDtqPuR0ezWy9Ptt&jbMo`vXL-cUB@Iabo|*Vl5^g&^bc+L3F{ z4vwRpqm6@A_DV|Pr0J=iA?x7upb$SCk9lE6{J8Lo^*y-;s6?4ub63jLI07`c^?7hX z!33TmiD?qjph0-0G*h3Td*8rv3Nn`F6kc3IoVA8`e4r>o1!1@w~o z8ZMI)sR(EIPij8^c_Ix4GCI9W(iSaX!*a}1$e)~v4GEWBMh#1de|D=sngvmkW%{PO zC(mHV2lQ;CnLL=;SO_Mja)i9@j8oiXq@6&$i7RhKJusgs4dw1lv^@P=lHhkq$mY*U z9M}LjBAd~`|7P>T|0Qx{>!UA#WDy}k0dKJ>sAXC`uZ`hzUsC?2OPPQsnYgBy5=7L2@Xfd$4%oL_a`C&7f`mIJSZwp^M&0)zI;2kjBUy>IFYY4K&g zwI39ukJML_)2Nl0&z7WWs&JFaXTa;(-9i5K!wmYEr+(s+g~U|#{4bukJ%?FX(i*+p zFD2fRi(cH%$LI%smSDB#Y>(b$=1>;W`K4iP;P zP#&Sffdh1{FeGM@0kKy)WK>LPgm{UF*vy*4sw!T07dx}!*22uy?s>_E8XG6CJ%lEe z#n}Tg#88KRf}?N;!e^Lz60rI}W6KhvQ8OqT{=ymaMNzXf>B^-hlr}|TB&`T9IT<}6 zF)$qYe8Wwd@fdKxg7+Gf>0a1TD~q2;Y`5N7>c*|<{HPxf_lF@$Q3cV>)vW77N(iel{DFFXint(2$F;&jEeJ7PRpU}43Gzma!WB+ z?9&L~Ufm81J7iIgVr9)IO*uI^x#H0%Vk|&c-vb&Xp#t{_5Y&4hsif{*V5QJ=p8>U= ziJ~v`&BxrB^qon_na25Fz#962FZmT|Qzi!g|6tqycW|6KuV1mYc-@yr69cJ4?G@+>|qr=kqxgeYua#Gv`#trD3}9xBCbg3WuB&Qa8xA% z!1jb{m}btrlXggzCh}eU!ztaDoDZa|_jZS8ele6`+Ob&XX>x*jz^Al0(>!b3)DLq)W z5Fj-P42De8C%w?=zB&W>7$5Wg9r)C~zT*GK8yM3wG{m#f;#sV7;IP6$CM2}bKqtdf z;ovFqDCa1=5kMZ~z%SjVatbZp&3 zd~8L8qDqP8Of!@d>=ll$ZV3oy{gjGiE)7KFrt0n17OKshSU1^FhhD(Nk02CS4at5x z+!ctx1qCPZR^y~$3z4MP!W?_?r_0}2u@F;)Jh z{RZp+zl+P5H)l{t%_ee0dlPr9O~I`VZpmHq9ui`;GM&&JP?0EPv{T_(O@ACJ>H1M zJ0Q^IBPMW%CQD~qFFdx*FnHT9+q)kkP0!iF^s??5-7KM`2JP*uGu#NMs_W_M$}24@ zqZEqI&Te-*)gw{*E9mS5e+hp(ZgJ^O%uBx}5It(-l(>1gy|a^FSV%!e7K-60BO}A> zc}3|esZc~pO1izhUGk;f2b5-!S1IzZ8bjPVj-?1DET#EtAk72TkYz?l2qkCT8O!l}Y;lu`F7u2{x+h&Re4f|Q#s2Iz zizA@N8Ho8LwjA8OaSK$$%e+xE_PG=UW-#OL}W#7OD| ztxkhN#H=;oz}9MNC)&#%iB0-@UBF^twVd8hRM*>Z6&ZaTjkCvWoNXa-9g|{S?*dyA z4Hws4C`DFGoW`)J4Q1zPfgx#X9tR!SiX72Xyga`ozNCKA$Hy?)tJ*oecvm7b7BT~? zP6>AJd*?7?wQsrgtVtK?TyK)&k;Yh)6)-I}mAzhH72YGXVU<9Uq%Vg0Oyqmh=4lTqKnV6q~PGksO8@oDMk*8}cGz zV$8p6Td!va<0-0Dk`HD);S{TMYb_HSi8?CR=YI&jS^N#i4FC$CEQJj(7lD?CM6je5 z%>Z|ruGrD%y{C}R%F`T(NsB|t4oVP&64;>fnfiCUG{sE% zd{|t*&$3OFI&e(+HZZoJLb%l92dRX#bncKw80N#7!D*A;Kk37{@-G@1^Esjjl^WSF zGe1iy<5Yg$vh3{Nm{(N5Z=mGl+c{j`+A}rA3`wbdAI#8}!2C^oM3BDHhZm034A0ki zaB^hSpi##8m3g&_WXOn=Cg^~8>c&3G;}0|ryS4k#Jkz-ju;4_ysgaDM6P?x6l8|qN zkleU4i5;u5e!Qep<;ProfFF$WpXjF=lC+>=5u2PEZNa`16w9-b7wv>}Y ze597Vl2+Qk6&eJj2$L-l}~zCuJ%~~g8WIO)G;NOdw#vBKwRj36>LYgE2i-lD`pnuB~7W{wAKsO zam(}lU+lAy^kf~!LC|5C)iRo-aHD-h$>w$mOVAO%s#~(nrFhyv@^ycCx?w`ZWse9& z;(03hdUFCKD@zuA^@vHb?rt+TL1c>ki`h5no%;Y%)dUG zk|RzaMb*5AB)7$QSHce44V+}s&rbufB=2|Qd_r-nxsE$-bs8PXwpu{1;y49Z_|T7? zwxXh<;etx?Fb4=f$MTjLj+7f?F1#9IQ;mPc%t{7bihgfgpRx7``=XKIivufn$C(YeqoM% z_dQlSJW6XrQ3_77gLaS(3IkW+%UD%`!SBS1)E}G~bk8zy&|a*af}1c17#}PCaWk(~ z8i_L=V^dorhg81HZXoK9cbe2qIIUd5lf~h%nQXvzt*1GwpJk<0ey0^Uy>WN${D%PQ zy=6qk;d~`YA!&rx8%QGT&~Sm;b>KWj8N)1#+S>GZE4-&dH$ah|m!S$wkj{I|V19$8 zs6bT;En!hW5f&@xFrc<5LQT)5QQd1;y)fb>)0{`;O_UJDM?R4{pW>TS5Ry+qj*Lz2 z=Za$?7yj#RTtc^WI-{pw=6}cEs*tsCS0PP1?=tBJ}Ge# z@3$bH&ZB)xc$wbrYWDq+uNSBz3*_S z#_!@FjL^enY6lnx+n(>O;Ea-~^aNcLtlF9Fl^62z-)~ku2nDG`LcGy-wE{#n(eHF- zAe9>@wyK-ta%NB)g;$z<7IdQ3XdRn-rx@?^4?T>BNeyAff zO&2^j4F55SEl~}er$^oc>MCn$xOOustL*a$=r=6PdbQiU_Uj!=)aZ`9w%XtOPv|2C z#+{dJT(92R&mo>HDAyyR7?NHFh#$D1%$1u3eHw~oWO);Up91f0>HbZv87myAa(!@Y zEUCnAMAK?_cNgb;Y5<=q@tSfF78m=j!zMpFCKRmygbWjkWdPd9TYI9QhYj$GYPw;Hx#Au{A;CaL=ermn;Y#-T@n4h=`jwM47RpepXa)%p6%L~oB_}IcNsF(-0+sPv+Vnj$GtQ){>)tnRaLGvvrp%}Y0_y2~_s8bcV zc`8DURKH|%!>JpXRi@j_+-LC)zS?Ln>alC2FEYJw+HOFrQvwI}JGRRPrJ|K#m$6>a z7x!2$VXOM3r+;6IpaNiF6?maY8M6@$Ehsncuh)EEorG&Nn_Zr-iadiVk9w)6=^*{kJ8Qe}II0h$Rsp z`n&1}c3re&=m;f2zg~&xme*7QFmqHErf;h*0JeWVkoWy<&6JcW_!mz~!_`VrXj$B& zb*K`go}gc~ws4BSYzKEc1o6;3f3CVXDpU2;qR-H1OZ3}6w$LI$4zW+{68Z0UYk@X+ zg%Hw$I`EGcQ*b0i<=sWE6?!1XUy)Z6rSfB}osFNCME*d0hO~O7(mDp8e0%)AfcL2_ zQVZt!X=t}e+P1NjJ5=IK13g}!33(yIWl3_&f%RC>XnqM85Nc8|N{rvQ3i-}vbRYcP za8d*>Ig{4L32SD{AtC}yW0{26bW~<~eTnwh{rztPoZ8O#Uqwo$HtfTitwC@Gmf&!* z=VmNLP)R9Hf`~@+yzvuAR@|MFF$jS40x=<6^&)-Qy$G^^t(4#_{IV7lS`h#pyE}q7 zQXzq?K?khv_^BJarXY$O074FF-)#f#p{_# zT?P^xt?}B&S$A&!w=*fLE9SOm*u{~?uzuvD+%uSLc=%cJgnd$br3?UndFX zI%H^Leri~cVTotHEyLT2)G#lqeXfKnmf(imZ1TLed>aAFB0lly$I?$!XPy+mv%EY7 zJyVyN9A}gN_#K3r=pSfL83a?s#TsQA!x;(noyFL@n#9Mr>Z{VgfhPIV}ph(kjuOuV8Q)3<*gNBK2<>sD4?3nr0^(0TsJT7)$hHOU&JU2%pDQMqa-Epoe~qN&f)o zQ&(5^ivwvrA02v3*&$uOePB`c+IATkHqlU16B9XxD_+G3D-n1^BV4etMMv~p2xA&c zev0V^9;XL)-nNAllt{wZ=P|LI5Ljw@hB`@8wLfX4qo%nMhJ_sknV(vm_T;S8b|735 z2oa(zCdw(dV(yG2#+qce(HRW3_A+_P1`?ut#GISX=IaJLOBuz;>j&hQ{9x=FD80*D z1a`9@Z>vT((4=Lm^#Unw(m3GhW=>A&hIov4jab%M-W4RY*Uy878E~}mD(n7E@AYr* zVArShoJQH85%IZ6l~G)qaHil9G zZRq(vxp+{}rO!L&hUNO&Rg$JuDeCMxkPb0YNx^jJ8hISsb4TIv`}YSy{lo@BnN{6I zO7sVxh2E|<^eSVf_w;nTFCH}?KgrL;@t9ms9hBewQs$klpIKll1m)%A#JH%Rm6Vx~ z#akL^eAN_{U!IwuXmPCH0(L_k-O|FFKDz7LoGG_=veK*?K@-*3{-MV5!0t0z{Nl^A zMv=)#I>%`kO_{=;1{^wlG7TNwG0=7(R8V?LqX*-9$KQuBVpo^Q;`s0I{0)CZ$bZNL z{rZ2#CsmqH8;8E5{iw@XbD{$D2g>sBX68Sflm4q{P5m`nIiwl#zk@2(;{Fq2#H-<>Gzwu_=jVFl44PQDZQjjDir7^!TtB> zxb~PZBz+3`ub>PZfSfpOd_`6N$2{l%k$GjOJzdI?h)1ys*Tw<^uLt(^mDFb9l=s)F z)>t~sfJaN%-2Y#MNL)uJ1NnVg8C_TzVcO-=a22W%pGfe{h~3Jc#8@i<&)>giT0yLW z$MuMjxHeo%hfTDIyv8#1wuAIxU)r(BIdo{y#{Skm>J=CXrJ`TmB%ASl)xKxA-(j;` zuUa6!75AeQlfw?B?qK0Bfdo$-;{?tRU~Q{3i(h$zx;B{ zw=0yCR@#4cdvWwxi+;Y)A%@#%a9(hLv;AhEqJncA9L zePCDWo+hyK&|wZkvjq5clm;|?J!j@N7T%me|p*x1-a2W2rskf{PmH*J!u`PAj#w(Yov z+DK70Y>aiH?Ku&jPg<__gLGE{8_lMT(pktW=Ug1{>Hq2deZZXB&ge2)I*Mg-d00VP za{YzHcc)oa(j7IQmoghr#nG1C>=YVOxx9#hjVZi=q{b$mWo51W4$bJBa+L#J=y34e z;{5yXNr^P-%syGZ&mJUt#dn~C54wNNld7ug23}xOgnj$c3(HCz77Z2{)+aI<6}@^8 z4PJGyw9|4nw&pX7r6CrWQcl@%z+BLo(5$?cN=L7^S?a35kBxcr0Oq<8~7pGRNQM@-(bV+C8f2?gY%al&?=)4|;jI`w?XDq#d~ z#?HgrW!KzB9G(Q?J}6@&e`wpw`a0q_j+gT1IfkBQ4T$7@Ac#{q?6M5tkzqGL67}pg zGd0Z6&MJe9j2OJ-*8ZRiye?2YEmLS!S}bq-@d{;9yJCOKrm-Fr6=oT3c0@J)5=%q0rlU#zsrA4waRrzR+_-F((*tSg9th+hh(+Paz#qxW z`8WWyg#xk_)R2BF)da}4DClPmY()#S0f#=~yG1ad2XkI0yQ-5S(0MVC!z32K31u

F~PRRh@+@ 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

~fh8%Pm+%9pp%wp#f9nXJx8dywrrBsFn( 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 literal 0 HcmV?d00001 diff --git a/src/webviews/apps/rebase/rebase.html b/src/webviews/apps/rebase/rebase.html index 50ce9c3..f98e1c6 100644 --- a/src/webviews/apps/rebase/rebase.html +++ b/src/webviews/apps/rebase/rebase.html @@ -27,10 +27,13 @@ alt ↓Move Down

- + -
diff --git a/src/webviews/apps/rebase/rebase.ts b/src/webviews/apps/rebase/rebase.ts index 6e85018..6bd7f07 100644 --- a/src/webviews/apps/rebase/rebase.ts +++ b/src/webviews/apps/rebase/rebase.ts @@ -7,6 +7,7 @@ import { RebaseDidAbortCommandType, RebaseDidChangeEntryCommandType, RebaseDidChangeNotificationType, + RebaseDidDisableCommandType, RebaseDidMoveEntryCommandType, RebaseDidStartCommandType, RebaseEntry, @@ -124,6 +125,7 @@ class RebaseEditor extends App { }), DOM.on('[data-action="start"]', 'click', () => this.onStartClicked()), DOM.on('[data-action="abort"]', 'click', () => this.onAbortClicked()), + DOM.on('[data-action="disable"]', 'click', () => this.onDisableClicked()), DOM.on('li[data-ref]', 'keydown', function (this: Element, e: KeyboardEvent) { if ((e.target as HTMLElement).matches('select[data-ref]')) { if (e.key === 'Escape') { @@ -134,6 +136,10 @@ class RebaseEditor extends App { } if (e.key === 'Enter' || e.key === ' ') { + if (e.key === 'Enter' && (e.target as HTMLElement).matches('a.entry-ref')) { + return; + } + const $select = (this as HTMLLIElement).querySelectorAll('select[data-ref]')[0]; if ($select != null) { $select.focus(); @@ -224,6 +230,10 @@ class RebaseEditor extends App { this.sendCommand(RebaseDidAbortCommandType, {}); } + private onDisableClicked() { + this.sendCommand(RebaseDidDisableCommandType, {}); + } + private onSelectChanged($el: HTMLSelectElement) { const ref = $el.dataset.ref; if (ref) { @@ -367,6 +377,8 @@ class RebaseEditor extends App { $select.appendChild(option); } $selectContainer.appendChild($select); + } else { + $entry.tabIndex = -1; } const $message = document.createElement('span'); diff --git a/src/webviews/apps/scss/buttons.scss b/src/webviews/apps/scss/buttons.scss index e03f38a..7455d4e 100644 --- a/src/webviews/apps/scss/buttons.scss +++ b/src/webviews/apps/scss/buttons.scss @@ -116,3 +116,64 @@ transition-duration: 0s !important; } } + +.button--flat-secondary { + background-color: var(--color-button-secondary-background); + border: 1px solid var(--color-button-secondary-background); + color: var(--color-button-foreground); + font-weight: 600; + transition: background-color 250ms, border-color 250ms, color 250ms; + + &:not([disabled]):hover, + &:not([disabled]):focus { + .vscode-dark & { + background-color: white; + border-color: white; + color: black; + } + + .vscode-light & { + background-color: var(--color-button-secondary-background--darken-30); + border-color: var(--color-button-secondary-background--darken-30); + color: white; + } + } + + .preload & { + transition-duration: 0s !important; + } +} + +.button--flat-subtle { + .vscode-light & { + border: 1px solid rgba(0, 0, 0, 0.2); + color: rgba(0, 0, 0, 0.6); + } + .vscode-dark & { + border: 1px solid rgba(255, 255, 255, 0.2); + color: rgba(255, 255, 255, 0.6); + } + transition: background-color 250ms, border-color 250ms, color 250ms; + + &:not([disabled]):hover, + &:not([disabled]):focus { + .vscode-light & { + background-color: var(--color-button-secondary-background--darken-30); + border-color: var(--color-button-secondary-background--darken-30); + color: white; + } + .vscode-dark & { + background-color: white; + border-color: white; + color: black; + } + } + + .preload & { + transition-duration: 0s !important; + } +} + +.button--right { + margin-left: auto; +} diff --git a/src/webviews/apps/scss/rebase.scss b/src/webviews/apps/scss/rebase.scss index 4eb3f9c..b76102a 100644 --- a/src/webviews/apps/scss/rebase.scss +++ b/src/webviews/apps/scss/rebase.scss @@ -11,7 +11,7 @@ body { font-size: 1.3em; grid-template-areas: 'header' 'entries' 'shortcuts' 'actions'; grid-template-columns: repeat(1, 1fr min-content); - margin: 1em auto; + margin: 0 auto; grid-gap: 0.5em 0; max-width: 1200px; min-width: 450px; @@ -20,11 +20,21 @@ body { header { display: flex; align-items: baseline; - margin: 0 0 1em 0; + margin: 0; + + h2 { + flex: auto 1 1; + margin-top: 0.5em; + font-size: 2.3rem; + } + + h4 { + flex: 100% 1 1; + } } h4 { - font-size: 1em; + font-size: 1.5rem; opacity: 0.8; } @@ -60,6 +70,7 @@ h4 { .actions { grid-area: actions; margin: 10px; + display: flex; } $entry-padding: 5px; @@ -95,6 +106,7 @@ $entry-padding: 5px; &.entry--base { margin-left: 10px; + margin-top: 5px; .vscode-dark & { background: rgba(255, 255, 255, 0.1); diff --git a/src/webviews/apps/settings/partials/rebase-editor.html b/src/webviews/apps/settings/partials/rebase-editor.html new file mode 100644 index 0000000..1a5ddbc --- /dev/null +++ b/src/webviews/apps/settings/partials/rebase-editor.html @@ -0,0 +1,39 @@ +
+
+
+ + + + + +
+ +

+ Adds a user-friendly interactive rebase editor to easily configure an interactive rebase session +

+
+ +
+
+
+ +
+ +
+
+
+
diff --git a/src/webviews/apps/settings/settings.html b/src/webviews/apps/settings/settings.html index f629c67..a065c5b 100644 --- a/src/webviews/apps/settings/settings.html +++ b/src/webviews/apps/settings/settings.html @@ -254,6 +254,8 @@ <%= require('html-loader!./partials/heatmap.html') %> + <%= require('html-loader!./partials/rebase-editor.html') %> + <%= require('html-loader!./partials/dates.html') %> <%= require('html-loader!./partials/menus.html') %> @@ -444,6 +446,16 @@ Interactive Rebase Editor + + +
  • + Dates & Times extends A case DidChangeConfigurationNotificationType.method: onIpcNotification(DidChangeConfigurationNotificationType, msg, params => { this.state.config = params.config; + this.state.customSettings = params.customSettings; this.updateState(); }); @@ -184,6 +185,11 @@ export abstract class AppWithConfig extends A break; } + case 'custom': { + this._changes[element.name] = element.checked; + + break; + } default: { if (element.checked) { this._changes[element.name] = fromCheckboxValue(element.value); @@ -311,7 +317,14 @@ export abstract class AppWithConfig extends A return state; } + private getCustomSettingValue(path: string): boolean | undefined { + return this.state.customSettings?.[path]; + } + private getSettingValue(path: string): T | undefined { + const customSetting = this.getCustomSettingValue(path); + if (customSetting != null) return customSetting as any; + return get(this.state.config, path); } @@ -320,7 +333,9 @@ export abstract class AppWithConfig extends A try { for (const el of document.querySelectorAll('input[type=checkbox][data-setting]')) { - if (el.dataset.settingType === 'array') { + if (el.dataset.settingType === 'custom') { + el.checked = this.getCustomSettingValue(el.name) ?? false; + } else if (el.dataset.settingType === 'array') { el.checked = (this.getSettingValue(el.name) ?? []).includes(el.value); } else if (el.dataset.valueOff != null) { const value = this.getSettingValue(el.name); diff --git a/src/webviews/apps/shared/theme.ts b/src/webviews/apps/shared/theme.ts index 70b2493..0989486 100644 --- a/src/webviews/apps/shared/theme.ts +++ b/src/webviews/apps/shared/theme.ts @@ -43,6 +43,10 @@ export function initializeAndWatchThemeColors() { bodyStyle.setProperty('--color-button-background', color); bodyStyle.setProperty('--color-button-background--darken-30', darken(color, 30)); + color = computedStyle.getPropertyValue('--vscode-button-secondaryBackground').trim(); + bodyStyle.setProperty('--color-button-secondary-background', color); + bodyStyle.setProperty('--color-button-secondary-background--darken-30', darken(color, 30)); + color = computedStyle.getPropertyValue('--vscode-button-background').trim(); bodyStyle.setProperty('--color-highlight', color); bodyStyle.setProperty('--color-highlight--75', opacity(color, 75)); diff --git a/src/webviews/protocol.ts b/src/webviews/protocol.ts index 6532c3a..77fbd58 100644 --- a/src/webviews/protocol.ts +++ b/src/webviews/protocol.ts @@ -37,6 +37,7 @@ export function onIpcNotification( export interface DidChangeConfigurationNotificationParams { config: Config; + customSettings: Record; } export const DidChangeConfigurationNotificationType = new IpcNotificationType( 'configuration/didChange', @@ -73,19 +74,20 @@ export interface DidPreviewConfigurationNotificationParams { id: string; preview: string; } -export const DidPreviewConfigurationNotificationType = new IpcNotificationType< - DidPreviewConfigurationNotificationParams ->('configuration/didPreview'); +export const DidPreviewConfigurationNotificationType = new IpcNotificationType( + 'configuration/didPreview', +); export interface SettingsDidRequestJumpToNotificationParams { anchor: string; } -export const SettingsDidRequestJumpToNotificationType = new IpcNotificationType< - SettingsDidRequestJumpToNotificationParams ->('settings/jumpTo'); +export const SettingsDidRequestJumpToNotificationType = new IpcNotificationType( + 'settings/jumpTo', +); export interface AppStateWithConfig { config: Config; + customSettings?: Record; } export interface SettingsState extends AppStateWithConfig { @@ -132,6 +134,8 @@ export const RebaseDidStartCommandType = new IpcCommandType('rebase/start'); export const RebaseDidAbortCommandType = new IpcCommandType('rebase/abort'); +export const RebaseDidDisableCommandType = new IpcCommandType('rebase/disable'); + export interface RebaseDidChangeEntryCommandParams { ref: string; action: RebaseEntryAction; diff --git a/src/webviews/rebaseEditor.ts b/src/webviews/rebaseEditor.ts index 2e7efec..7462c67 100644 --- a/src/webviews/rebaseEditor.ts +++ b/src/webviews/rebaseEditor.ts @@ -2,6 +2,7 @@ import { TextDecoder } from 'util'; import { CancellationToken, + ConfigurationTarget, CustomTextEditorProvider, Disposable, Position, @@ -15,6 +16,7 @@ import { WorkspaceEdit, } from 'vscode'; import { ShowQuickCommitCommand } from '../commands'; +import { configuration } from '../configuration'; import { Container } from '../container'; import { Logger } from '../logger'; import { debug } from '../system'; @@ -26,6 +28,7 @@ import { RebaseDidAbortCommandType, RebaseDidChangeEntryCommandType, RebaseDidChangeNotificationType, + RebaseDidDisableCommandType, RebaseDidMoveEntryCommandType, RebaseDidStartCommandType, RebaseEntry, @@ -79,6 +82,64 @@ export class RebaseEditorProvider implements CustomTextEditorProvider, Disposabl this._disposable.dispose(); } + get enabled(): boolean { + const associations = configuration.inspectAny<{ viewType: string; filenamePattern: string }[]>( + 'workbench.editorAssociations', + )?.globalValue; + if (associations == null || associations.length === 0) return true; + + const association = associations.find(a => a.filenamePattern === 'git-rebase-todo'); + return association != null ? association.viewType === 'gitlens.rebase' : true; + } + + private _disableAfterNextUse: boolean = false; + async enableForNextUse() { + if (!this.enabled) { + await this.setEnabled(true); + this._disableAfterNextUse = true; + } + } + + async setEnabled(enabled: boolean): Promise { + this._disableAfterNextUse = false; + + const inspection = configuration.inspectAny<{ viewType: string; filenamePattern: string }[]>( + 'workbench.editorAssociations', + ); + + let associations = inspection?.globalValue; + if (associations == null || associations.length === 0) { + if (enabled) return; + + associations = [ + { + viewType: 'default', + filenamePattern: 'git-rebase-todo', + }, + ]; + } else { + const index = associations.findIndex(a => a.filenamePattern === 'git-rebase-todo'); + if (index !== -1) { + if (enabled) { + if (associations.length === 1) { + associations = undefined; + } else { + associations.splice(index, 1); + } + } else { + associations[index].viewType = 'default'; + } + } else if (!enabled) { + associations.push({ + viewType: 'default', + filenamePattern: 'git-rebase-todo', + }); + } + } + + await configuration.updateAny('workbench.editorAssociations', associations, ConfigurationTarget.Global); + } + @debug({ args: false }) async resolveCustomTextEditor(document: TextDocument, panel: WebviewPanel, _token: CancellationToken) { const disposable = Disposable.from( @@ -95,6 +156,11 @@ export class RebaseEditorProvider implements CustomTextEditorProvider, Disposabl panel.webview.options = { enableCommandUris: true, enableScripts: true }; panel.webview.html = await this.getHtml(panel.webview, document); + + if (this._disableAfterNextUse) { + this._disableAfterNextUse = false; + void this.setEnabled(false); + } } private parseEntries(contents: string): RebaseEntry[]; @@ -228,28 +294,24 @@ export class RebaseEditorProvider implements CustomTextEditorProvider, Disposabl // break; - case RebaseDidStartCommandType.method: - onIpcCommand(RebaseDidStartCommandType, e, async _params => { - // Avoid triggering events by disposing them first - disposable.dispose(); + case RebaseDidDisableCommandType.method: + onIpcCommand(RebaseDidDisableCommandType, e, async () => { + await this.abort(document, panel, disposable); + await this.setEnabled(false); + }); - await document.save(); - panel.dispose(); + break; + + case RebaseDidStartCommandType.method: + onIpcCommand(RebaseDidStartCommandType, e, async () => { + await this.rebase(document, panel, disposable); }); break; case RebaseDidAbortCommandType.method: - onIpcCommand(RebaseDidAbortCommandType, e, async _params => { - // Avoid triggering events by disposing them first - disposable.dispose(); - - // Delete the contents to abort the rebase - const edit = new WorkspaceEdit(); - edit.replace(document.uri, new Range(0, 0, document.lineCount, 0), ''); - await workspace.applyEdit(edit); - await document.save(); - panel.dispose(); + onIpcCommand(RebaseDidAbortCommandType, e, async () => { + await this.abort(document, panel, disposable); }); break; @@ -395,6 +457,26 @@ export class RebaseEditorProvider implements CustomTextEditorProvider, Disposabl } } + private async abort(document: TextDocument, panel: WebviewPanel, disposable: Disposable) { + // Avoid triggering events by disposing them first + disposable.dispose(); + + // Delete the contents to abort the rebase + const edit = new WorkspaceEdit(); + edit.replace(document.uri, new Range(0, 0, document.lineCount, 0), ''); + await workspace.applyEdit(edit); + await document.save(); + panel.dispose(); + } + + private async rebase(document: TextDocument, panel: WebviewPanel, disposable: Disposable) { + // Avoid triggering events by disposing them first + disposable.dispose(); + + await document.save(); + panel.dispose(); + } + private async getHtml(webview: Webview, document: TextDocument): Promise { const uri = Uri.joinPath(Container.context.extensionUri, 'dist', 'webviews', 'rebase.html'); const content = new TextDecoder('utf8').decode(await workspace.fs.readFile(uri)); diff --git a/src/webviews/settingsWebview.ts b/src/webviews/settingsWebview.ts index 77523de..7c1228c 100644 --- a/src/webviews/settingsWebview.ts +++ b/src/webviews/settingsWebview.ts @@ -95,6 +95,7 @@ export class SettingsWebview extends WebviewBase { const bootstrap: SettingsState = { // Make sure to get the raw config, not from the container which has the modes mixed in config: configuration.get(), + customSettings: this.getCustomSettings(), scope: 'user', scopes: scopes, }; diff --git a/src/webviews/webviewBase.ts b/src/webviews/webviewBase.ts index 06846fa..19b3674 100644 --- a/src/webviews/webviewBase.ts +++ b/src/webviews/webviewBase.ts @@ -56,6 +56,7 @@ export abstract class WebviewBase implements Disposable { constructor(showCommand: Commands, private readonly _column?: ViewColumn) { this.disposable = Disposable.from( configuration.onDidChange(this.onConfigurationChanged, this), + configuration.onDidChangeAny(this.onAnyConfigurationChanged, this), commands.registerCommand(showCommand, this.onShowCommand, this), ); } @@ -77,10 +78,57 @@ export abstract class WebviewBase implements Disposable { this._disposablePanel?.dispose(); } + private _customSettings: + | Map< + string, + { + name: string; + enabled: () => boolean; + update: (enabled: boolean) => Promise; + } + > + | undefined; + private get customSettings() { + if (this._customSettings == null) { + this._customSettings = new Map< + string, + { + name: string; + enabled: () => boolean; + update: (enabled: boolean) => Promise; + } + >([ + [ + 'rebaseEditor.enabled', + { + name: 'workbench.editorAssociations', + enabled: () => Container.rebaseEditor.enabled, + update: Container.rebaseEditor.setEnabled, + }, + ], + ]); + } + return this._customSettings; + } + protected onShowCommand() { void this.show(this._column); } + private onAnyConfigurationChanged(e: ConfigurationChangeEvent) { + let notify = false; + for (const setting of this.customSettings.values()) { + if (e.affectsConfiguration(setting.name)) { + notify = true; + break; + } + } + + if (!notify) return; + + void this.notifyDidChangeConfiguration(); + } + private onConfigurationChanged(_e: ConfigurationChangeEvent) { void this.notifyDidChangeConfiguration(); } @@ -110,9 +158,17 @@ export abstract class WebviewBase implements Disposable { params.scope === 'workspace' ? ConfigurationTarget.Workspace : ConfigurationTarget.Global; for (const key in params.changes) { + let value = params.changes[key]; + + const customSetting = this.customSettings.get(key); + if (customSetting != null) { + await customSetting.update(value); + + continue; + } + const inspect = configuration.inspect(key as any)!; - let value = params.changes[key]; if (value != null) { if (params.scope === 'workspace') { if (value === inspect.workspaceValue) continue; @@ -292,9 +348,20 @@ export abstract class WebviewBase implements Disposable { return this.postMessage({ id: nextIpcId(), method: type.method, params: params }); } + protected getCustomSettings(): Record { + const customSettings = Object.create(null); + for (const [key, setting] of this.customSettings) { + customSettings[key] = setting.enabled(); + } + return customSettings; + } + private notifyDidChangeConfiguration() { // Make sure to get the raw config, not from the container which has the modes mixed in - return this.notify(DidChangeConfigurationNotificationType, { config: configuration.get() }); + return this.notify(DidChangeConfigurationNotificationType, { + config: configuration.get(), + customSettings: this.getCustomSettings(), + }); } private postMessage(message: IpcMessage) {