@@ -310,3 +310,197 @@ func TestImporter_Import(t *testing.T) {
310310 })
311311 }
312312}
313+
314+ func TestImporter_Import_VSCodeVariant (t * testing.T ) {
315+ mappingConfig , err := mappings .NewTestMappingConfig ()
316+ require .NoError (t , err )
317+
318+ // Inline the variant-specific test actions instead of sourcing them from the YAML fixture.
319+ mappingConfig .Mappings ["actions.test.variantConfig" ] = mappings.ActionMappingConfig {
320+ ID : "actions.test.variantConfig" ,
321+ Description : "Test VSCode variant config priority" ,
322+ Category : "Testing" ,
323+ VSCode : mappings.VscodeConfigs {
324+ {Command : "vscode.default.command" , When : "editorTextFocus" },
325+ },
326+ Windsurf : mappings.VscodeConfigs {
327+ {Command : "windsurf.specific.command" , When : "windsurf.cascadePanel.focused" },
328+ },
329+ Cursor : mappings.VscodeConfigs {
330+ {Command : "cursor.specific.command" , When : "cursorContext" },
331+ },
332+ }
333+
334+ mappingConfig .Mappings ["actions.test.variantFallback" ] = mappings.ActionMappingConfig {
335+ ID : "actions.test.variantFallback" ,
336+ Description : "Test VSCode variant fallback to vscode config" ,
337+ Category : "Testing" ,
338+ VSCode : mappings.VscodeConfigs {
339+ {Command : "vscode.fallback.command" , When : "editorTextFocus" },
340+ },
341+ }
342+
343+ parseKB := func (s string ) keybinding.Keybinding {
344+ kb , err := keybinding .NewKeybinding (s , keybinding.ParseOption {Platform : platform .PlatformMacOS , Separator : "+" })
345+ if err != nil {
346+ panic (err )
347+ }
348+ return kb
349+ }
350+
351+ tests := []struct {
352+ name string
353+ editorType pluginapi.EditorType
354+ jsonContent string
355+ expected keymap.Keymap
356+ }{
357+ {
358+ name : "windsurf uses windsurf-specific config" ,
359+ editorType : pluginapi .EditorTypeWindsurf ,
360+ jsonContent : `[
361+ {
362+ "key": "cmd+m",
363+ "command": "windsurf.specific.command",
364+ "when": "windsurf.cascadePanel.focused"
365+ }
366+ ]` ,
367+ expected : keymap.Keymap {
368+ Actions : []keymap.Action {
369+ {
370+ Name : "actions.test.variantConfig" ,
371+ Bindings : []keybinding.Keybinding {parseKB ("meta+m" )},
372+ },
373+ },
374+ },
375+ },
376+ {
377+ name : "cursor uses cursor-specific config" ,
378+ editorType : pluginapi .EditorTypeCursor ,
379+ jsonContent : `[
380+ {
381+ "key": "cmd+m",
382+ "command": "cursor.specific.command",
383+ "when": "cursorContext"
384+ }
385+ ]` ,
386+ expected : keymap.Keymap {
387+ Actions : []keymap.Action {
388+ {
389+ Name : "actions.test.variantConfig" ,
390+ Bindings : []keybinding.Keybinding {parseKB ("meta+m" )},
391+ },
392+ },
393+ },
394+ },
395+ {
396+ name : "vscode uses vscode config (no variant override)" ,
397+ editorType : pluginapi .EditorTypeVSCode ,
398+ jsonContent : `[
399+ {
400+ "key": "cmd+m",
401+ "command": "vscode.default.command",
402+ "when": "editorTextFocus"
403+ }
404+ ]` ,
405+ expected : keymap.Keymap {
406+ Actions : []keymap.Action {
407+ {
408+ Name : "actions.test.variantConfig" ,
409+ Bindings : []keybinding.Keybinding {parseKB ("meta+m" )},
410+ },
411+ },
412+ },
413+ },
414+ {
415+ name : "windsurf falls back to vscode config when no windsurf config" ,
416+ editorType : pluginapi .EditorTypeWindsurf ,
417+ jsonContent : `[
418+ {
419+ "key": "cmd+f",
420+ "command": "vscode.fallback.command",
421+ "when": "editorTextFocus"
422+ }
423+ ]` ,
424+ expected : keymap.Keymap {
425+ Actions : []keymap.Action {
426+ {
427+ Name : "actions.test.variantFallback" ,
428+ Bindings : []keybinding.Keybinding {parseKB ("meta+f" )},
429+ },
430+ },
431+ },
432+ },
433+ {
434+ name : "cursor falls back to vscode config when no cursor config" ,
435+ editorType : pluginapi .EditorTypeCursor ,
436+ jsonContent : `[
437+ {
438+ "key": "cmd+f",
439+ "command": "vscode.fallback.command",
440+ "when": "editorTextFocus"
441+ }
442+ ]` ,
443+ expected : keymap.Keymap {
444+ Actions : []keymap.Action {
445+ {
446+ Name : "actions.test.variantFallback" ,
447+ Bindings : []keybinding.Keybinding {parseKB ("meta+f" )},
448+ },
449+ },
450+ },
451+ },
452+ {
453+ name : "windsurf-next uses windsurf config" ,
454+ editorType : pluginapi .EditorTypeWindsurfNext ,
455+ jsonContent : `[
456+ {
457+ "key": "cmd+m",
458+ "command": "windsurf.specific.command",
459+ "when": "windsurf.cascadePanel.focused"
460+ }
461+ ]` ,
462+ expected : keymap.Keymap {
463+ Actions : []keymap.Action {
464+ {
465+ Name : "actions.test.variantConfig" ,
466+ Bindings : []keybinding.Keybinding {parseKB ("meta+m" )},
467+ },
468+ },
469+ },
470+ },
471+ }
472+
473+ for _ , tt := range tests {
474+ t .Run (tt .name , func (t * testing.T ) {
475+ logger := slog .New (slog .NewTextHandler (os .Stdout , nil ))
476+ recorder := metrics .NewNoop ()
477+
478+ var plugin pluginapi.Plugin
479+ switch tt .editorType {
480+ case pluginapi .EditorTypeWindsurf :
481+ plugin = NewWindsurf (mappingConfig , logger , recorder )
482+ case pluginapi .EditorTypeWindsurfNext :
483+ plugin = NewWindsurfNext (mappingConfig , logger , recorder )
484+ case pluginapi .EditorTypeCursor :
485+ plugin = NewCursor (mappingConfig , logger , recorder )
486+ default :
487+ plugin = New (mappingConfig , logger , recorder )
488+ }
489+
490+ importer , err := plugin .Importer ()
491+ require .NoError (t , err )
492+
493+ reader := strings .NewReader (tt .jsonContent )
494+ result , err := importer .Import (context .Background (), reader , pluginapi.PluginImportOption {})
495+ require .NoError (t , err )
496+
497+ assert .True (
498+ t ,
499+ reflect .DeepEqual (tt .expected , result .Keymap ),
500+ "Expected %v, got %v" ,
501+ tt .expected ,
502+ result .Keymap ,
503+ )
504+ })
505+ }
506+ }
0 commit comments