@@ -450,202 +450,6 @@ function registerCoreCommands(context: vscode.ExtensionContext): void {
450450 } )
451451 ) ;
452452
453- // Manage bookmarks - tag-style UI
454- context . subscriptions . push (
455- vscode . commands . registerCommand ( 'open-jj.bookmark.manage' , async ( arg ?: Change | { change : Change } ) => {
456- if ( ! repository ) {
457- return ;
458- }
459-
460- const change = arg && 'change' in arg ? arg . change : arg ;
461- const targetRevision = change ?. changeIdShort ?? '@' ;
462- const targetChangeId = change ?. changeId ?? repository . currentChange ?. changeId ;
463-
464- // Get bookmarks on this change
465- const bookmarksOnChange = repository . bookmarks . filter (
466- b => ! b . isRemote && targetChangeId && b . changeId === targetChangeId
467- ) ;
468- const otherBookmarks = repository . bookmarks . filter (
469- b => ! b . isRemote && ( ! targetChangeId || b . changeId !== targetChangeId )
470- ) ;
471-
472- interface ActionItem extends vscode . QuickPickItem {
473- action : 'remove' | 'add' | 'create' ;
474- bookmarkName ?: string ;
475- }
476-
477- const showPicker = async ( ) => {
478- // Refresh bookmark lists
479- // Compare using startsWith since bookmark changeId might be short
480- const isOnChange = ( b : { changeId : string } ) => {
481- if ( ! targetChangeId ) return false ;
482- return targetChangeId . startsWith ( b . changeId ) || b . changeId . startsWith ( targetChangeId ) ;
483- } ;
484-
485- const currentOnChange = repository ! . bookmarks . filter (
486- b => ! b . isRemote && isOnChange ( b )
487- ) ;
488- const currentOther = repository ! . bookmarks . filter (
489- b => ! b . isRemote && ! isOnChange ( b )
490- ) ;
491-
492- const buildItems = ( filter : string ) : ActionItem [ ] => {
493- const items : ActionItem [ ] = [ ] ;
494- const filterLower = filter . toLowerCase ( ) ;
495-
496- // Current bookmarks on this change (removable)
497- const matchingOnChange = currentOnChange . filter ( b => b . name . toLowerCase ( ) . includes ( filterLower ) ) ;
498- if ( matchingOnChange . length > 0 ) {
499- items . push ( {
500- label : 'On this change' ,
501- kind : vscode . QuickPickItemKind . Separator ,
502- action : 'remove' ,
503- } ) ;
504- for ( const b of matchingOnChange ) {
505- items . push ( {
506- label : `$(close) ${ b . name } ` ,
507- description : 'click to remove' ,
508- action : 'remove' ,
509- bookmarkName : b . name ,
510- } ) ;
511- }
512- }
513-
514- // Other bookmarks (can be moved here)
515- const matchingOther = currentOther . filter ( b => b . name . toLowerCase ( ) . includes ( filterLower ) ) ;
516- if ( matchingOther . length > 0 ) {
517- items . push ( {
518- label : 'Move to this change' ,
519- kind : vscode . QuickPickItemKind . Separator ,
520- action : 'add' ,
521- } ) ;
522- for ( const b of matchingOther ) {
523- items . push ( {
524- label : `$(add) ${ b . name } ` ,
525- description : b . changeId . slice ( 0 , 8 ) ,
526- action : 'add' ,
527- bookmarkName : b . name ,
528- } ) ;
529- }
530- }
531-
532- // Add "Create xxx" option if there's text and no exact match
533- const allBookmarks = [ ...currentOnChange , ...currentOther ] ;
534- const hasExactMatch = allBookmarks . some ( b => b . name . toLowerCase ( ) === filterLower ) ;
535- if ( filter . trim ( ) && ! hasExactMatch ) {
536- items . push ( {
537- label : `$(plus) Create "${ filter . trim ( ) } "` ,
538- description : 'Create new bookmark' ,
539- action : 'create' ,
540- bookmarkName : filter . trim ( ) ,
541- } ) ;
542- } else {
543- // Create new option (static)
544- items . push ( {
545- label : 'Create new bookmark...' ,
546- kind : vscode . QuickPickItemKind . Separator ,
547- action : 'create' ,
548- } ) ;
549- items . push ( {
550- label : '$(plus) Create new bookmark' ,
551- description : 'type a name for the new bookmark' ,
552- action : 'create' ,
553- } ) ;
554- }
555-
556- return items ;
557- } ;
558-
559- const quickPick = vscode . window . createQuickPick < ActionItem > ( ) ;
560- quickPick . title = `Bookmarks on ${ change ?. changeIdShort ?? '@' } ` ;
561- quickPick . placeholder = currentOnChange . length > 0
562- ? `Current: ${ currentOnChange . map ( b => b . name ) . join ( ', ' ) } `
563- : 'No bookmarks on this change' ;
564- quickPick . items = buildItems ( '' ) ;
565- quickPick . matchOnDescription = true ;
566-
567- quickPick . onDidChangeValue ( ( value ) => {
568- quickPick . items = buildItems ( value ) ;
569- } ) ;
570-
571- const picked = await new Promise < ActionItem | undefined > ( ( resolve ) => {
572- quickPick . onDidAccept ( ( ) => {
573- resolve ( quickPick . selectedItems [ 0 ] ) ;
574- quickPick . hide ( ) ;
575- } ) ;
576- quickPick . onDidHide ( ( ) => {
577- resolve ( undefined ) ;
578- quickPick . dispose ( ) ;
579- } ) ;
580- quickPick . show ( ) ;
581- } ) ;
582-
583- if ( ! picked || picked . kind === vscode . QuickPickItemKind . Separator ) {
584- return ;
585- }
586-
587- if ( picked . action === 'remove' && picked . bookmarkName ) {
588- // Remove = move to a new empty change (abandon it from here)
589- // Actually in jj we can't easily "remove" a bookmark, we just move it
590- // Let's ask where to move it or delete it
591- const choice = await vscode . window . showQuickPick ( [
592- { label : '$(trash) Delete bookmark' , value : 'delete' } ,
593- { label : '$(arrow-right) Move to different change...' , value : 'move' } ,
594- ] , {
595- title : `What to do with "${ picked . bookmarkName } "?` ,
596- } ) ;
597-
598- if ( choice ?. value === 'delete' ) {
599- await repository ! . deleteBookmark ( picked . bookmarkName ) ;
600- vscode . window . showInformationMessage ( `Deleted bookmark "${ picked . bookmarkName } "` ) ;
601- } else if ( choice ?. value === 'move' ) {
602- const targetChange = await vscode . window . showInputBox ( {
603- prompt : 'Enter change ID to move bookmark to' ,
604- placeHolder : 'e.g., abc123' ,
605- } ) ;
606- if ( targetChange ) {
607- await repository ! . setBookmark ( picked . bookmarkName , targetChange ) ;
608- vscode . window . showInformationMessage ( `Moved "${ picked . bookmarkName } " to ${ targetChange } ` ) ;
609- }
610- }
611- await showPicker ( ) ; // Show picker again
612- } else if ( picked . action === 'add' && picked . bookmarkName ) {
613- await repository ! . setBookmark ( picked . bookmarkName , targetRevision ) ;
614- vscode . window . showInformationMessage ( `Moved "${ picked . bookmarkName } " here` ) ;
615- await showPicker ( ) ; // Show picker again
616- } else if ( picked . action === 'create' ) {
617- let name = picked . bookmarkName ;
618- if ( ! name ) {
619- name = await vscode . window . showInputBox ( {
620- prompt : 'Enter new bookmark name' ,
621- placeHolder : 'bookmark-name' ,
622- validateInput : ( v ) => {
623- if ( ! v ?. trim ( ) ) return 'Name required' ;
624- if ( ! / ^ [ \w \- . / ] + $ / . test ( v ) ) return 'Invalid characters' ;
625- if ( repository ! . bookmarks . some ( b => b . name === v ) ) return 'Already exists' ;
626- return null ;
627- } ,
628- } ) ;
629- }
630- if ( name ) {
631- // Validate the name
632- if ( ! / ^ [ \w \- . / ] + $ / . test ( name ) ) {
633- vscode . window . showErrorMessage ( 'Invalid bookmark name' ) ;
634- } else if ( repository ! . bookmarks . some ( b => b . name === name ) ) {
635- vscode . window . showErrorMessage ( 'Bookmark already exists' ) ;
636- } else {
637- await repository ! . createBookmark ( name , targetRevision ) ;
638- vscode . window . showInformationMessage ( `Created bookmark "${ name } "` ) ;
639- }
640- }
641- await showPicker ( ) ; // Show picker again
642- }
643- } ;
644-
645- await showPicker ( ) ;
646- } )
647- ) ;
648-
649453 // Create bookmark (simple version, kept for compatibility)
650454 context . subscriptions . push (
651455 vscode . commands . registerCommand ( 'open-jj.bookmark.create' , async ( arg ?: Change | { change : Change } ) => {
0 commit comments