@@ -3,7 +3,7 @@ import * as path from "path";
33import * as fs from "fs" ;
44
55import { NoteItem , NotesTreeProvider } from "./treeView" ;
6- import { createCommandName } from "./utils" ;
6+ import { createCommandName , getNotesDir } from "./utils" ;
77import { NotesCodeLensProvider } from "./codelens" ;
88
99export function gerRefreshTreeCommand (
@@ -26,7 +26,7 @@ export function getCreateNoteCommand(
2626 return vscode . commands . registerCommand (
2727 createCommandName ( "createNote" ) ,
2828 async ( ) => {
29- const NOTES_DIR = context . globalStorageUri . fsPath ;
29+ const NOTES_DIR = getNotesDir ( context ) ;
3030
3131 const noteName = await vscode . window . showInputBox ( {
3232 prompt : "Enter note name" ,
@@ -63,7 +63,7 @@ export function getSelectNoteCommand(
6363 return vscode . commands . registerCommand (
6464 createCommandName ( "selectNote" ) ,
6565 async ( ) => {
66- const NOTES_DIR = context . globalStorageUri . fsPath ;
66+ const NOTES_DIR = getNotesDir ( context ) ;
6767 const files = fs . readdirSync ( NOTES_DIR ) . filter ( ( f ) => f . endsWith ( ".md" ) ) ;
6868
6969 if ( files . length === 0 ) {
@@ -78,7 +78,7 @@ export function getSelectNoteCommand(
7878 } ) ;
7979
8080 if ( selected ) {
81- const NOTES_DIR = context . globalStorageUri . fsPath ;
81+ const NOTES_DIR = getNotesDir ( context ) ;
8282
8383 const currentNote = path . join ( NOTES_DIR , selected ) ;
8484 context . workspaceState . update ( "currentNote" , currentNote ) ;
@@ -255,7 +255,7 @@ export function getOpenNotesDirCommand(context: vscode.ExtensionContext) {
255255 return vscode . commands . registerCommand (
256256 createCommandName ( "openNotesDir" ) ,
257257 ( ) => {
258- const NOTES_DIR = context . globalStorageUri . fsPath ;
258+ const NOTES_DIR = getNotesDir ( context ) ;
259259 vscode . env . openExternal ( vscode . Uri . file ( NOTES_DIR ) ) ;
260260 }
261261 ) ;
@@ -308,3 +308,222 @@ export function getViewNoteAtCommand() {
308308 }
309309 ) ;
310310}
311+
312+ export function getSearchNotesCommand ( context : vscode . ExtensionContext ) {
313+ // Command: Search notes
314+ return vscode . commands . registerCommand (
315+ createCommandName ( "searchNotes" ) ,
316+ async ( ) => {
317+ const NOTES_DIR = getNotesDir ( context ) ;
318+
319+ const searchQuery = await vscode . window . showInputBox ( {
320+ prompt : "Search in notes (annotations, file names, code)" ,
321+ placeHolder : "Enter search term..." ,
322+ } ) ;
323+
324+ if ( ! searchQuery || searchQuery . trim ( ) === "" ) {
325+ return ;
326+ }
327+
328+ const query = searchQuery . toLowerCase ( ) ;
329+ const results : Array < {
330+ noteName : string ;
331+ notePath : string ;
332+ matches : Array < {
333+ type : "title" | "annotation" | "code" | "filename" ;
334+ line : number ;
335+ fileName ?: string ;
336+ content : string ;
337+ preview : string ;
338+ } > ;
339+ } > = [ ] ;
340+
341+ // Search through all notes
342+ const noteFiles = fs
343+ . readdirSync ( NOTES_DIR )
344+ . filter ( ( f ) => f . endsWith ( ".md" ) ) ;
345+
346+ for ( const noteFile of noteFiles ) {
347+ const notePath = path . join ( NOTES_DIR , noteFile ) ;
348+ const content = fs . readFileSync ( notePath , "utf-8" ) ;
349+ const lines = content . split ( "\n" ) ;
350+ const noteName = path . basename ( noteFile , ".md" ) ;
351+ const noteMatches : ( typeof results ) [ 0 ] [ "matches" ] = [ ] ;
352+
353+ // Check note title
354+ if ( noteName . toLowerCase ( ) . includes ( query ) ) {
355+ noteMatches . push ( {
356+ type : "title" ,
357+ line : 1 ,
358+ content : noteName ,
359+ preview : `Note title: ${ noteName } ` ,
360+ } ) ;
361+ }
362+
363+ // Parse sections and search
364+ let currentSection : {
365+ fileName ?: string ;
366+ lineNum ?: number ;
367+ annotation ?: string ;
368+ code ?: string ;
369+ } = { } ;
370+ let inCodeBlock = false ;
371+ let codeLines : string [ ] = [ ] ;
372+
373+ for ( let i = 0 ; i < lines . length ; i ++ ) {
374+ const line = lines [ i ] ;
375+ const lineNum = i + 1 ;
376+
377+ // Detect section headers (## filename:line)
378+ const sectionMatch = line . match ( / ^ # # ( .+ ?) : ( \d + ) / ) ;
379+ if ( sectionMatch ) {
380+ // Process previous section if it had matches
381+ if ( currentSection . fileName ) {
382+ const sectionContent = [
383+ currentSection . annotation ,
384+ currentSection . code ,
385+ ]
386+ . filter ( Boolean )
387+ . join ( " " )
388+ . toLowerCase ( ) ;
389+
390+ if ( sectionContent . includes ( query ) ) {
391+ if ( currentSection . annotation ?. toLowerCase ( ) . includes ( query ) ) {
392+ noteMatches . push ( {
393+ type : "annotation" ,
394+ line : lineNum ,
395+ fileName : currentSection . fileName ,
396+ content : currentSection . annotation ! ,
397+ preview : `${ currentSection . fileName } :${ currentSection . lineNum } - ${ currentSection . annotation } ` ,
398+ } ) ;
399+ }
400+ if ( currentSection . code ?. toLowerCase ( ) . includes ( query ) ) {
401+ noteMatches . push ( {
402+ type : "code" ,
403+ line : lineNum ,
404+ fileName : currentSection . fileName ,
405+ content : currentSection . code ! ,
406+ preview : `${ currentSection . fileName } :${ currentSection . lineNum } - Code snippet` ,
407+ } ) ;
408+ }
409+ }
410+ }
411+
412+ // Start new section
413+ currentSection = {
414+ fileName : sectionMatch [ 1 ] ,
415+ lineNum : parseInt ( sectionMatch [ 2 ] ) ,
416+ annotation : undefined ,
417+ code : undefined ,
418+ } ;
419+ codeLines = [ ] ;
420+ inCodeBlock = false ;
421+ }
422+
423+ // Extract annotation
424+ const noteMatch = line . match ( / \* \* N o t e : \* \* ( .+ ) / ) ;
425+ if ( noteMatch ) {
426+ currentSection . annotation = noteMatch [ 1 ] ;
427+ }
428+
429+ // Track code blocks
430+ if ( line . startsWith ( "```" ) ) {
431+ inCodeBlock = ! inCodeBlock ;
432+ continue ;
433+ }
434+
435+ if ( inCodeBlock ) {
436+ codeLines . push ( line ) ;
437+ }
438+ }
439+
440+ // Process last section
441+ if ( currentSection . fileName ) {
442+ currentSection . code = codeLines . join ( "\n" ) ;
443+ const sectionContent = [
444+ currentSection . annotation ,
445+ currentSection . code ,
446+ ]
447+ . filter ( Boolean )
448+ . join ( " " )
449+ . toLowerCase ( ) ;
450+
451+ if ( sectionContent . includes ( query ) ) {
452+ if ( currentSection . annotation ?. toLowerCase ( ) . includes ( query ) ) {
453+ noteMatches . push ( {
454+ type : "annotation" ,
455+ line : lines . length ,
456+ fileName : currentSection . fileName ,
457+ content : currentSection . annotation ! ,
458+ preview : `${ currentSection . fileName } :${ currentSection . lineNum } - ${ currentSection . annotation } ` ,
459+ } ) ;
460+ }
461+ if ( currentSection . code ?. toLowerCase ( ) . includes ( query ) ) {
462+ noteMatches . push ( {
463+ type : "code" ,
464+ line : lines . length ,
465+ fileName : currentSection . fileName ,
466+ content : currentSection . code ! ,
467+ preview : `${ currentSection . fileName } :${ currentSection . lineNum } - Code snippet` ,
468+ } ) ;
469+ }
470+ }
471+ }
472+
473+ if ( noteMatches . length > 0 ) {
474+ results . push ( {
475+ noteName,
476+ notePath,
477+ matches : noteMatches ,
478+ } ) ;
479+ }
480+ }
481+
482+ // Display results
483+ if ( results . length === 0 ) {
484+ vscode . window . showInformationMessage (
485+ `No results found for "${ searchQuery } "`
486+ ) ;
487+ return ;
488+ }
489+
490+ // Create quick pick items
491+ const items = results . flatMap ( ( result ) => {
492+ return result . matches . map ( ( match ) => {
493+ let icon = "$(file)" ;
494+ if ( match . type === "title" ) {
495+ icon = "$(notebook)" ;
496+ } else if ( match . type === "annotation" ) {
497+ icon = "$(note)" ;
498+ } else if ( match . type === "code" ) {
499+ icon = "$(code)" ;
500+ }
501+
502+ return {
503+ label : `${ icon } ${ result . noteName } ` ,
504+ description : match . preview ,
505+ detail :
506+ match . type === "code"
507+ ? match . content . substring ( 0 , 100 ) +
508+ ( match . content . length > 100 ? "..." : "" )
509+ : undefined ,
510+ notePath : result . notePath ,
511+ } ;
512+ } ) ;
513+ } ) ;
514+
515+ const selected = await vscode . window . showQuickPick ( items , {
516+ placeHolder : `Found ${ items . length } result${
517+ items . length === 1 ? "" : "s"
518+ } for "${ searchQuery } "`,
519+ matchOnDescription : true ,
520+ matchOnDetail : true ,
521+ } ) ;
522+
523+ if ( selected ) {
524+ const doc = await vscode . workspace . openTextDocument ( selected . notePath ) ;
525+ await vscode . window . showTextDocument ( doc ) ;
526+ }
527+ }
528+ ) ;
529+ }
0 commit comments