@@ -466,11 +466,17 @@ export async function searchSvnCommits(query: string, cwd: string): Promise<SvnC
466466
467467 const commits : SvnCommit [ ] = [ ]
468468
469- // If query looks like a revision number, search for that specific revision
470- if ( / ^ \d + $ / . test ( query ) ) {
471- SvnLogger . debug ( "Query looks like revision number, searching for specific revision" , { revision : query } )
469+ // If query looks like a revision number with 'r' prefix, search for that specific revision
470+ // Only support "r123" format, not pure numbers
471+ const revisionMatch = query . match ( / ^ r ( \d + ) $ / i)
472+ if ( revisionMatch ) {
473+ const revisionNumber = revisionMatch [ 1 ]
474+ SvnLogger . debug ( "Query looks like revision number, searching for specific revision" , {
475+ originalQuery : query ,
476+ revision : revisionNumber ,
477+ } )
472478 try {
473- const command = `svn log -r ${ query } --xml`
479+ const command = `svn log -r ${ revisionNumber } --xml`
474480 SvnLogger . debug ( "Executing revision search command" , { command, cwd } )
475481
476482 const { stdout } = await execAsync ( command , { cwd } )
@@ -502,10 +508,21 @@ export async function searchSvnCommits(query: string, cwd: string): Promise<SvnC
502508 const allCommits = parseSvnLogXml ( stdout )
503509 SvnLogger . debug ( "Parsed all commits" , { count : allCommits . length } )
504510
505- // Filter commits by message content
506- const messageMatches = allCommits . filter (
507- ( commit ) => commit . message . toLowerCase ( ) . includes ( query . toLowerCase ( ) ) || commit . revision === query ,
508- )
511+ // Filter commits by message content or revision match
512+ const messageMatches = allCommits . filter ( ( commit ) => {
513+ // Check message content match
514+ const messageMatch = commit . message . toLowerCase ( ) . includes ( query . toLowerCase ( ) )
515+
516+ // Check revision match (only handle "r123" format, not pure numbers)
517+ let revisionMatch = false
518+ const revisionMatchResult = query . match ( / ^ r ( \d + ) $ / i)
519+ if ( revisionMatchResult ) {
520+ const queryRevision = revisionMatchResult [ 1 ]
521+ revisionMatch = commit . revision === queryRevision
522+ }
523+
524+ return messageMatch || revisionMatch
525+ } )
509526 SvnLogger . debug ( "Filtered commits by message" , { matchCount : messageMatches . length , query } )
510527
511528 // Add unique commits (avoid duplicates from revision search)
@@ -735,29 +752,108 @@ export async function getSvnCommitInfoForMentions(revision: string, cwd: string)
735752 }
736753 console . log ( "[DEBUG] Clean revision:" , cleanRevision )
737754
738- const { stdout } = await execAsync ( `svn log -r ${ cleanRevision } -v` , { cwd } )
755+ // Use UTF-8 encoding to handle Chinese characters properly
756+ const { stdout } = await execAsync ( `svn log -r ${ cleanRevision } -v` , {
757+ cwd,
758+ encoding : "utf8" ,
759+ } )
739760 console . log ( "[DEBUG] SVN log output:" , stdout )
740761
762+ // Parse the log output more carefully
741763 const lines = stdout . split ( "\n" )
742- const logEntry = lines . find ( ( line ) => line . includes ( "r" + cleanRevision ) )
743- if ( ! logEntry ) {
764+
765+ // Find the header line (contains revision info)
766+ const headerLineIndex = lines . findIndex ( ( line ) => line . includes ( `r${ cleanRevision } |` ) )
767+ if ( headerLineIndex === - 1 ) {
744768 return `Revision ${ revision } not found`
745769 }
746770
747- const parts = logEntry . split ( "|" ) . map ( ( part ) => part . trim ( ) )
748- if ( parts . length >= 4 ) {
749- const [ rev , author , date ] = parts
750- const messageStart = stdout . indexOf ( "\n\n" )
751- const messageEnd = stdout . indexOf ( "\n---" , messageStart )
752- const message =
753- messageStart !== - 1 && messageEnd !== - 1
754- ? stdout . substring ( messageStart + 2 , messageEnd ) . trim ( )
755- : "No message"
771+ const headerLine = lines [ headerLineIndex ]
772+ const parts = headerLine . split ( "|" ) . map ( ( part ) => part . trim ( ) )
756773
757- return `${ rev } by ${ author } on ${ date } \n${ message } `
774+ if ( parts . length < 3 ) {
775+ return `Revision ${ revision } : Unable to parse commit information`
758776 }
759777
760- return `Revision ${ revision } : Unable to parse commit information`
778+ const [ rev , author , dateInfo ] = parts
779+ // Extract just the date part, ignore the Chinese day name to avoid encoding issues
780+ const dateMatch = dateInfo . match ( / ( \d { 4 } - \d { 2 } - \d { 2 } \d { 2 } : \d { 2 } : \d { 2 } [ + - ] \d { 4 } ) / )
781+ const date = dateMatch ? dateMatch [ 1 ] : dateInfo . split ( "(" ) [ 0 ] . trim ( )
782+
783+ // Find the commit message (after "Changed paths:" section)
784+ let message = "No message"
785+ let changedPaths = ""
786+
787+ // Look for "Changed paths:" section
788+ const changedPathsIndex = lines . findIndex ( ( line ) => line . includes ( "Changed paths:" ) )
789+ if ( changedPathsIndex !== - 1 ) {
790+ // Extract changed paths
791+ const pathLines = [ ]
792+ for ( let i = changedPathsIndex + 1 ; i < lines . length ; i ++ ) {
793+ const line = lines [ i ]
794+ if ( line . trim ( ) === "" || line . startsWith ( "---" ) ) {
795+ break
796+ }
797+ if ( line . trim ( ) . match ( / ^ [ A M D R C ] \s + \/ / ) ) {
798+ pathLines . push ( line . trim ( ) )
799+ }
800+ }
801+ changedPaths = pathLines . join ( "\n" )
802+
803+ // Find message after the changed paths section
804+ for ( let i = changedPathsIndex + 1 ; i < lines . length ; i ++ ) {
805+ const line = lines [ i ]
806+ if ( line . trim ( ) === "" && i + 1 < lines . length ) {
807+ // Check if next line is not a separator and not empty
808+ const nextLine = lines [ i + 1 ]
809+ if ( nextLine && ! nextLine . startsWith ( "---" ) && nextLine . trim ( ) !== "" ) {
810+ // Found the message
811+ const messageLines = [ ]
812+ for ( let j = i + 1 ; j < lines . length ; j ++ ) {
813+ const msgLine = lines [ j ]
814+ if ( msgLine . startsWith ( "---" ) ) {
815+ break
816+ }
817+ if ( msgLine . trim ( ) !== "" ) {
818+ messageLines . push ( msgLine )
819+ }
820+ }
821+ if ( messageLines . length > 0 ) {
822+ message = messageLines . join ( "\n" ) . trim ( )
823+ }
824+ break
825+ }
826+ }
827+ }
828+ }
829+
830+ // Get diff information (same as getSvnCommitInfo function)
831+ let diff = ""
832+ try {
833+ console . log ( "[DEBUG] Getting diff for revision:" , cleanRevision )
834+ const { stdout : diffOutput } = await execAsync ( `svn diff -c ${ cleanRevision } ` , {
835+ cwd,
836+ encoding : "utf8" ,
837+ } )
838+ diff = truncateOutput ( diffOutput , SVN_OUTPUT_LINE_LIMIT )
839+ console . log ( "[DEBUG] Diff length:" , diff . length )
840+ } catch ( error ) {
841+ const svnError = error instanceof Error ? error : new Error ( String ( error ) )
842+ console . log ( "[DEBUG] Diff not available for revision:" , svnError . message )
843+ }
844+
845+ // Format the result with changed files and diff
846+ let result = `${ rev } by ${ author } on ${ date } \n${ message } `
847+
848+ if ( changedPaths ) {
849+ result += `\n\nChanged files:\n${ changedPaths } `
850+ }
851+
852+ if ( diff && diff . trim ( ) ) {
853+ result += `\n\nDiff:\n${ diff } `
854+ }
855+
856+ return result
761857 } catch ( error ) {
762858 const svnError = error instanceof Error ? error : new Error ( String ( error ) )
763859 console . error ( "[DEBUG] Error getting SVN commit info for mentions:" , svnError )
0 commit comments