@@ -14,10 +14,11 @@ const props = defineProps<{
1414}>()
1515
1616// Selected commit hash state
17- const selectedCommitHashes = ref <string []>([])
17+ const selectedCommitHashes = defineModel <string []>({ default: [] })
18+
1819const isDragging = ref (false )
19- const dragStartIndex = ref <number | null >(null )
20- const dragEndIndex = ref <number | null >( null )
20+ const selectionStart = ref <number | null >(null )
21+ const dragEndIndex = ref <number >( 0 )
2122
2223const ITEMS_PER_PAGE = 45
2324const currentPage = ref (1 )
@@ -46,8 +47,9 @@ const visibleCommits = computed(() => {
4647})
4748
4849function handleCommitSelected(hash : string , index : number , event : MouseEvent ) {
50+ isDragging .value = true
51+
4952 if (event .shiftKey && selectedCommitHashes .value .length > 0 ) {
50- // Range selection with shift key
5153 const lastSelectedIndex = visibleCommits .value .findIndex (
5254 commit => commit .hash === selectedCommitHashes .value [selectedCommitHashes .value .length - 1 ],
5355 )
@@ -62,21 +64,66 @@ function handleCommitSelected(hash: string, index: number, event: MouseEvent) {
6264 selectedCommitHashes .value = [... new Set ([... selectedCommitHashes .value , ... hashesToSelect ])]
6365 }
6466 }
67+ else if (event .ctrlKey || event .metaKey ) {
68+ if (selectedCommitHashes .value .includes (hash )) {
69+ selectedCommitHashes .value = selectedCommitHashes .value .filter (h => h !== hash )
70+ }
71+ else {
72+ selectedCommitHashes .value .push (hash )
73+ }
74+ }
6575 else {
6676 selectedCommitHashes .value = [hash ]
6777 }
6878
69- try {
70- if (window .vscode ) {
79+ handleMouseUp ()
80+ }
81+
82+ function handleMouseDown(index : number , event : MouseEvent ) {
83+ const target = event .target as HTMLElement
84+ if (target .closest (' .copy-button' )) {
85+ return
86+ }
87+
88+ if (! event .ctrlKey && ! event .metaKey && ! event .shiftKey ) {
89+ isDragging .value = true
90+ selectionStart .value = index
91+ dragEndIndex .value = index
92+ selectedCommitHashes .value = [visibleCommits .value [index ].hash ]
93+ }
94+ }
95+
96+ function handleMouseOver(index : number ) {
97+ if (isDragging .value && selectionStart .value !== null ) {
98+ const startIdx = Math .min (selectionStart .value , index )
99+ const endIdx = Math .max (selectionStart .value , index )
100+ const hashesToSelect = visibleCommits .value
101+ .slice (startIdx , endIdx + 1 )
102+ .map (commit => commit .hash )
103+
104+ selectedCommitHashes .value = hashesToSelect
105+ }
106+ }
107+
108+ function handleMouseUp() {
109+ const wasDragging = isDragging .value
110+
111+ isDragging .value = false
112+
113+ if (wasDragging ) {
114+ try {
71115 window .vscode .postMessage ({
72116 command: WEBVIEW_CHANNEL .SHOW_COMMIT_DETAILS ,
73117 commitHashes: JSON .stringify (toRaw (selectedCommitHashes .value )),
74118 })
75119 }
120+ catch (error ) {
121+ console .error (' Error sending commit details:' , error )
122+ }
76123 }
77- catch ( error ) {
78- console . error ( ' Error sending commit details: ' , error )
79- }
124+
125+ // 最后重置选择起点
126+ selectionStart . value = null
80127}
81128
82129onMounted (() => {
@@ -100,15 +147,20 @@ onUnmounted(() => {
100147 </script >
101148
102149<template >
103- <div class =" git-graph" @mouseleave =" isDragging = false " >
150+ <div class =" git-graph" @mouseleave =" handleMouseUp " @mouseup = " handleMouseUp " >
104151 <ul class =" commit-list" >
105152 <ColumnHeader v-model =" columnWidths" />
106153 <ListItem
107154 v-for =" (commit, index) in visibleCommits" :key =" commit.hash" :graph-data =" graphData[index]"
108155 :prev-graph-data =" index > 0 ? graphData[index - 1] : null"
109156 :next-graph-data =" index < graphData.length - 1 ? graphData[index + 1] : null" :commit =" commit"
110- :column-widths =" columnWidths" :is-selected =" selectedCommitHashes.includes(commit.hash)"
111- @select =" (event) => handleCommitSelected(commit.hash, index, event)"
157+ :column-widths =" columnWidths" :is-selected =" selectedCommitHashes.includes(commit.hash)" :class =" {
158+ 'being-dragged': isDragging && selectionStart !== null
159+ && ((index >= selectionStart && index <= dragEndIndex)
160+ || (index <= selectionStart && index >= dragEndIndex)),
161+ }" @select =" (event) => handleCommitSelected(commit.hash, index, event)"
162+ @mousedown =" (event: MouseEvent) => handleMouseDown(index, event)"
163+ @mouseover =" () => isDragging && handleMouseOver(index)"
112164 />
113165 <li ref =" loadingTriggerRef" class =" loading-trigger" >
114166 <div v-if =" visibleCommits.length < commitData.length" class =" loading-text" >
@@ -124,6 +176,8 @@ onUnmounted(() => {
124176 width : 100% ;
125177 overflow : auto ;
126178 font-family : var (--vscode-editor-font-family );
179+ user-select : none ;
180+ /* Prevent text selection during drag */
127181}
128182
129183.commit-list {
@@ -145,4 +199,8 @@ onUnmounted(() => {
145199 font-size : 12px ;
146200 color : var (--vscode-descriptionForeground );
147201}
202+
203+ .being-dragged {
204+ background-color : var (--vscode-list-activeSelectionBackground , rgba (0 , 0 , 0 , 0.1 ));
205+ }
148206 </style >
0 commit comments