@@ -10,7 +10,7 @@ import { IDisposable, Disposable, DisposableStore, combinedDisposable } from 'vs
1010import { ViewPane , IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer' ;
1111import { append , $ , addClass , toggleClass , removeClass , Dimension } from 'vs/base/browser/dom' ;
1212import { IListVirtualDelegate , IIdentityProvider } from 'vs/base/browser/ui/list/list' ;
13- import { ISCMResourceGroup , ISCMResource , InputValidationType , ISCMService , ISCMRepository , ISCMInput } from 'vs/workbench/contrib/scm/common/scm' ;
13+ import { ISCMResourceGroup , ISCMResource , InputValidationType , ISCMService , ISCMRepository , ISCMInput , IInputValidation } from 'vs/workbench/contrib/scm/common/scm' ;
1414import { ResourceLabels , IResourceLabel } from 'vs/workbench/browser/labels' ;
1515import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge' ;
1616import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
@@ -78,6 +78,7 @@ import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
7878import { Command } from 'vs/editor/common/modes' ;
7979import { renderCodicons } from 'vs/base/common/codicons' ;
8080import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar' ;
81+ import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview' ;
8182
8283type TreeElement = ISCMRepository | ISCMInput | ISCMResourceGroup | IResourceNode < ISCMResource , ISCMResourceGroup > | ISCMResource ;
8384
@@ -1179,20 +1180,24 @@ class SCMInputWidget extends Disposable {
11791180 private element : HTMLElement ;
11801181 private editorContainer : HTMLElement ;
11811182 private placeholderTextContainer : HTMLElement ;
1182- private validationContainer : HTMLElement ;
11831183 private inputEditor : CodeEditorWidget ;
11841184
11851185 private model : { readonly input : ISCMInput ; readonly textModel : ITextModel ; } | undefined ;
11861186 private repositoryContextKey : IContextKey < ISCMRepository | undefined > ;
11871187 private repositoryDisposables = new DisposableStore ( ) ;
11881188
1189+ private validation : IInputValidation | undefined ;
1190+ private validationDisposable : IDisposable = Disposable . None ;
1191+
11891192 readonly onDidChangeContentHeight : Event < void > ;
11901193
11911194 get input ( ) : ISCMInput | undefined {
11921195 return this . model ?. input ;
11931196 }
11941197
11951198 set input ( input : ISCMInput | undefined ) {
1199+ this . validationDisposable . dispose ( ) ;
1200+
11961201 this . repositoryDisposables . dispose ( ) ;
11971202 this . repositoryDisposables = new DisposableStore ( ) ;
11981203 this . repositoryContextKey . set ( input ?. repository ) ;
@@ -1229,25 +1234,8 @@ class SCMInputWidget extends Disposable {
12291234 const offset = position && textModel . getOffsetAt ( position ) ;
12301235 const value = textModel . getValue ( ) ;
12311236
1232- const result = await input . validateInput ( value , offset || 0 ) ;
1233-
1234- if ( ! result ) {
1235- removeClass ( this . editorContainer , 'validation-info' ) ;
1236- removeClass ( this . editorContainer , 'validation-warning' ) ;
1237- removeClass ( this . editorContainer , 'validation-error' ) ;
1238- removeClass ( this . validationContainer , 'validation-info' ) ;
1239- removeClass ( this . validationContainer , 'validation-warning' ) ;
1240- removeClass ( this . validationContainer , 'validation-error' ) ;
1241- this . validationContainer . textContent = null ;
1242- } else {
1243- toggleClass ( this . editorContainer , 'validation-info' , result . type === InputValidationType . Information ) ;
1244- toggleClass ( this . editorContainer , 'validation-warning' , result . type === InputValidationType . Warning ) ;
1245- toggleClass ( this . editorContainer , 'validation-error' , result . type === InputValidationType . Error ) ;
1246- toggleClass ( this . validationContainer , 'validation-info' , result . type === InputValidationType . Information ) ;
1247- toggleClass ( this . validationContainer , 'validation-warning' , result . type === InputValidationType . Warning ) ;
1248- toggleClass ( this . validationContainer , 'validation-error' , result . type === InputValidationType . Error ) ;
1249- this . validationContainer . textContent = result . message ;
1250- }
1237+ this . validation = await input . validateInput ( value , offset || 0 ) ;
1238+ this . renderValidation ( ) ;
12511239 } ;
12521240
12531241 const triggerValidation = ( ) => validationDelayer . trigger ( validate ) ;
@@ -1324,13 +1312,13 @@ class SCMInputWidget extends Disposable {
13241312 @IKeybindingService private keybindingService : IKeybindingService ,
13251313 @IConfigurationService private configurationService : IConfigurationService ,
13261314 @IInstantiationService instantiationService : IInstantiationService ,
1315+ @IContextViewService private readonly contextViewService : IContextViewService ,
13271316 ) {
13281317 super ( ) ;
13291318
13301319 this . element = append ( container , $ ( '.scm-editor' ) ) ;
13311320 this . editorContainer = append ( this . element , $ ( '.scm-editor-container' ) ) ;
13321321 this . placeholderTextContainer = append ( this . editorContainer , $ ( '.scm-editor-placeholder' ) ) ;
1333- this . validationContainer = append ( this . editorContainer , $ ( '.scm-editor-validation' ) ) ;
13341322
13351323 const contextKeyService2 = contextKeyService . createScoped ( this . element ) ;
13361324 this . repositoryContextKey = contextKeyService2 . createKey ( 'scmRepository' , undefined ) ;
@@ -1368,8 +1356,14 @@ class SCMInputWidget extends Disposable {
13681356 this . inputEditor = instantiationService2 . createInstance ( CodeEditorWidget , this . editorContainer , editorOptions , codeEditorWidgetOptions ) ;
13691357 this . _register ( this . inputEditor ) ;
13701358
1371- this . _register ( this . inputEditor . onDidFocusEditorText ( ( ) => addClass ( this . editorContainer , 'synthetic-focus' ) ) ) ;
1372- this . _register ( this . inputEditor . onDidBlurEditorText ( ( ) => removeClass ( this . editorContainer , 'synthetic-focus' ) ) ) ;
1359+ this . _register ( this . inputEditor . onDidFocusEditorText ( ( ) => {
1360+ addClass ( this . editorContainer , 'synthetic-focus' ) ;
1361+ this . renderValidation ( ) ;
1362+ } ) ) ;
1363+ this . _register ( this . inputEditor . onDidBlurEditorText ( ( ) => {
1364+ removeClass ( this . editorContainer , 'synthetic-focus' ) ;
1365+ this . validationDisposable . dispose ( ) ;
1366+ } ) ) ;
13731367
13741368 const onInputFontFamilyChanged = Event . filter ( this . configurationService . onDidChangeConfiguration , e => e . affectsConfiguration ( 'scm.inputFontFamily' ) ) ;
13751369 this . _register ( onInputFontFamilyChanged ( ( ) => this . inputEditor . updateOptions ( { fontFamily : this . getInputEditorFontFamily ( ) } ) ) ) ;
@@ -1390,6 +1384,33 @@ class SCMInputWidget extends Disposable {
13901384 } ;
13911385
13921386 this . inputEditor . layout ( dimension ) ;
1387+ this . renderValidation ( ) ;
1388+ }
1389+
1390+ private renderValidation ( ) : void {
1391+ this . validationDisposable . dispose ( ) ;
1392+
1393+ toggleClass ( this . editorContainer , 'validation-info' , this . validation ?. type === InputValidationType . Information ) ;
1394+ toggleClass ( this . editorContainer , 'validation-warning' , this . validation ?. type === InputValidationType . Warning ) ;
1395+ toggleClass ( this . editorContainer , 'validation-error' , this . validation ?. type === InputValidationType . Error ) ;
1396+
1397+ if ( ! this . validation || ! this . inputEditor . hasTextFocus ( ) ) {
1398+ return ;
1399+ }
1400+
1401+ this . validationDisposable = this . contextViewService . showContextView ( {
1402+ getAnchor : ( ) => this . editorContainer ,
1403+ render : container => {
1404+ const element = append ( container , $ ( '.scm-editor-validation' ) ) ;
1405+ toggleClass ( element , 'validation-info' , this . validation ! . type === InputValidationType . Information ) ;
1406+ toggleClass ( element , 'validation-warning' , this . validation ! . type === InputValidationType . Warning ) ;
1407+ toggleClass ( element , 'validation-error' , this . validation ! . type === InputValidationType . Error ) ;
1408+ element . style . width = `${ this . editorContainer . clientWidth } px` ;
1409+ element . textContent = this . validation ! . message ;
1410+ return Disposable . None ;
1411+ } ,
1412+ anchorAlignment : AnchorAlignment . LEFT
1413+ } ) ;
13931414 }
13941415
13951416 private getInputEditorFontFamily ( ) : string {
@@ -1405,6 +1426,12 @@ class SCMInputWidget extends Disposable {
14051426
14061427 return this . defaultInputFontFamily ;
14071428 }
1429+
1430+ dispose ( ) : void {
1431+ this . repositoryDisposables . dispose ( ) ;
1432+ this . validationDisposable . dispose ( ) ;
1433+ super . dispose ( ) ;
1434+ }
14081435}
14091436
14101437export class SCMViewPane extends ViewPane {
@@ -1678,82 +1705,82 @@ export class SCMViewPane extends ViewPane {
16781705registerThemingParticipant ( ( theme , collector ) => {
16791706 const inputBackgroundColor = theme . getColor ( inputBackground ) ;
16801707 if ( inputBackgroundColor ) {
1681- collector . addRule ( `.scm-viewlet .scm-editor-container .monaco-editor-background,
1682- .scm-viewlet .scm-editor-container .monaco-editor,
1683- .scm-viewlet .scm-editor-container .monaco-editor .margin
1708+ collector . addRule ( `.scm-view .scm-editor-container .monaco-editor-background,
1709+ .scm-view .scm-editor-container .monaco-editor,
1710+ .scm-view .scm-editor-container .monaco-editor .margin
16841711 { background-color: ${ inputBackgroundColor } ; }` ) ;
16851712 }
16861713
16871714 const inputForegroundColor = theme . getColor ( inputForeground ) ;
16881715 if ( inputForegroundColor ) {
1689- collector . addRule ( `.scm-viewlet .scm-editor-container .mtk1 { color: ${ inputForegroundColor } ; }` ) ;
1716+ collector . addRule ( `.scm-view .scm-editor-container .mtk1 { color: ${ inputForegroundColor } ; }` ) ;
16901717 }
16911718
16921719 const inputBorderColor = theme . getColor ( inputBorder ) ;
16931720 if ( inputBorderColor ) {
1694- collector . addRule ( `.scm-viewlet .scm-editor-container { outline: 1px solid ${ inputBorderColor } ; }` ) ;
1721+ collector . addRule ( `.scm-view .scm-editor-container { outline: 1px solid ${ inputBorderColor } ; }` ) ;
16951722 }
16961723
16971724 const focusBorderColor = theme . getColor ( focusBorder ) ;
16981725 if ( focusBorderColor ) {
1699- collector . addRule ( `.scm-viewlet .scm-editor-container.synthetic-focus { outline: 1px solid ${ focusBorderColor } ; }` ) ;
1726+ collector . addRule ( `.scm-view .scm-editor-container.synthetic-focus { outline: 1px solid ${ focusBorderColor } ; }` ) ;
17001727 }
17011728
17021729 const inputPlaceholderForegroundColor = theme . getColor ( inputPlaceholderForeground ) ;
17031730 if ( inputPlaceholderForegroundColor ) {
1704- collector . addRule ( `.scm-viewlet .scm-editor-placeholder { color: ${ inputPlaceholderForegroundColor } ; }` ) ;
1731+ collector . addRule ( `.scm-view .scm-editor-placeholder { color: ${ inputPlaceholderForegroundColor } ; }` ) ;
17051732 }
17061733
17071734 const inputValidationInfoBorderColor = theme . getColor ( inputValidationInfoBorder ) ;
17081735 if ( inputValidationInfoBorderColor ) {
1709- collector . addRule ( `.scm-viewlet .scm-editor-container.validation-info { outline: 1px solid ${ inputValidationInfoBorderColor } ; }` ) ;
1710- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-info { border: 1px solid ${ inputValidationInfoBorderColor } ; }` ) ;
1736+ collector . addRule ( `.scm-view .scm-editor-container.validation-info { outline: 1px solid ${ inputValidationInfoBorderColor } ; }` ) ;
1737+ collector . addRule ( `.scm-editor-validation.validation-info { border-color: ${ inputValidationInfoBorderColor } ; }` ) ;
17111738 }
17121739
17131740 const inputValidationInfoBackgroundColor = theme . getColor ( inputValidationInfoBackground ) ;
17141741 if ( inputValidationInfoBackgroundColor ) {
1715- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-info { background-color: ${ inputValidationInfoBackgroundColor } ; }` ) ;
1742+ collector . addRule ( `.scm-editor-validation.validation-info { background-color: ${ inputValidationInfoBackgroundColor } ; }` ) ;
17161743 }
17171744
17181745 const inputValidationInfoForegroundColor = theme . getColor ( inputValidationInfoForeground ) ;
17191746 if ( inputValidationInfoForegroundColor ) {
1720- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-info { color: ${ inputValidationInfoForegroundColor } ; }` ) ;
1747+ collector . addRule ( `.scm-editor-validation.validation-info { color: ${ inputValidationInfoForegroundColor } ; }` ) ;
17211748 }
17221749
17231750 const inputValidationWarningBorderColor = theme . getColor ( inputValidationWarningBorder ) ;
17241751 if ( inputValidationWarningBorderColor ) {
1725- collector . addRule ( `.scm-viewlet .scm-editor-container.validation-warning { outline: 1px solid ${ inputValidationWarningBorderColor } ; }` ) ;
1726- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-warning { border: 1px solid ${ inputValidationWarningBorderColor } ; }` ) ;
1752+ collector . addRule ( `.scm-view .scm-editor-container.validation-warning { outline: 1px solid ${ inputValidationWarningBorderColor } ; }` ) ;
1753+ collector . addRule ( `.scm-editor-validation.validation-warning { border-color: ${ inputValidationWarningBorderColor } ; }` ) ;
17271754 }
17281755
17291756 const inputValidationWarningBackgroundColor = theme . getColor ( inputValidationWarningBackground ) ;
17301757 if ( inputValidationWarningBackgroundColor ) {
1731- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-warning { background-color: ${ inputValidationWarningBackgroundColor } ; }` ) ;
1758+ collector . addRule ( `.scm-editor-validation.validation-warning { background-color: ${ inputValidationWarningBackgroundColor } ; }` ) ;
17321759 }
17331760
17341761 const inputValidationWarningForegroundColor = theme . getColor ( inputValidationWarningForeground ) ;
17351762 if ( inputValidationWarningForegroundColor ) {
1736- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-warning { color: ${ inputValidationWarningForegroundColor } ; }` ) ;
1763+ collector . addRule ( `.scm-editor-validation.validation-warning { color: ${ inputValidationWarningForegroundColor } ; }` ) ;
17371764 }
17381765
17391766 const inputValidationErrorBorderColor = theme . getColor ( inputValidationErrorBorder ) ;
17401767 if ( inputValidationErrorBorderColor ) {
1741- collector . addRule ( `.scm-viewlet .scm-editor-container.validation-error { outline: 1px solid ${ inputValidationErrorBorderColor } ; }` ) ;
1742- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-error { border: 1px solid ${ inputValidationErrorBorderColor } ; }` ) ;
1768+ collector . addRule ( `.scm-view .scm-editor-container.validation-error { outline: 1px solid ${ inputValidationErrorBorderColor } ; }` ) ;
1769+ collector . addRule ( `.scm-editor-validation.validation-error { border-color: ${ inputValidationErrorBorderColor } ; }` ) ;
17431770 }
17441771
17451772 const inputValidationErrorBackgroundColor = theme . getColor ( inputValidationErrorBackground ) ;
17461773 if ( inputValidationErrorBackgroundColor ) {
1747- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-error { background-color: ${ inputValidationErrorBackgroundColor } ; }` ) ;
1774+ collector . addRule ( `.scm-editor-validation.validation-error { background-color: ${ inputValidationErrorBackgroundColor } ; }` ) ;
17481775 }
17491776
17501777 const inputValidationErrorForegroundColor = theme . getColor ( inputValidationErrorForeground ) ;
17511778 if ( inputValidationErrorForegroundColor ) {
1752- collector . addRule ( `.scm-viewlet .scm- editor-validation.validation-error { color: ${ inputValidationErrorForegroundColor } ; }` ) ;
1779+ collector . addRule ( `.scm-editor-validation.validation-error { color: ${ inputValidationErrorForegroundColor } ; }` ) ;
17531780 }
17541781
17551782 const repositoryStatusActionsBorderColor = theme . getColor ( SIDE_BAR_BORDER ) ;
17561783 if ( repositoryStatusActionsBorderColor ) {
1757- collector . addRule ( `.scm-viewlet .scm-provider > .status > .monaco-action-bar > .actions-container { border-color: ${ repositoryStatusActionsBorderColor } ; }` ) ;
1784+ collector . addRule ( `.scm-view .scm-provider > .status > .monaco-action-bar > .actions-container { border-color: ${ repositoryStatusActionsBorderColor } ; }` ) ;
17581785 }
17591786} ) ;
0 commit comments