| 794 | } |
| 795 | |
| 796 | func (v *Vault) ListNotes() ([]NoteMeta, error) { |
| 797 | v.mu.RLock() |
| 798 | defer v.mu.RUnlock() |
| 799 | v.hydratePersistedNoteMetaCache() |
| 800 | |
| 801 | type noteFile struct { |
| 802 | folder NoteFolder |
| 803 | path string |
| 804 | } |
| 805 | |
| 806 | files := []noteFile{} |
| 807 | for _, folder := range AllFolders { |
| 808 | folderRoot, err := v.folderRoot(folder) |
| 809 | if err != nil { |
| 810 | return nil, err |
| 811 | } |
| 812 | isPrimaryRoot := folder == FolderInbox && filepath.Clean(folderRoot) == filepath.Clean(v.root) |
| 813 | err = filepath.WalkDir(folderRoot, func(path string, d os.DirEntry, err error) error { |
| 814 | if err != nil { |
| 815 | if isSkippableWalkErr(err) { |
| 816 | return nil |
| 817 | } |
| 818 | return err |
| 819 | } |
| 820 | if d.IsDir() { |
| 821 | if strings.HasPrefix(d.Name(), ".") && path != folderRoot { |
| 822 | return filepath.SkipDir |
| 823 | } |
| 824 | if isFormDirName(d.Name()) { |
| 825 | return filepath.SkipDir // database folder — not loose notes |
| 826 | } |
| 827 | if isPrimaryRoot && path != folderRoot { |
| 828 | parent := filepath.Dir(path) |
| 829 | if filepath.Clean(parent) == filepath.Clean(folderRoot) { |
| 830 | if shouldHidePrimaryRootName(d.Name()) { |
| 831 | return filepath.SkipDir |
| 832 | } |
| 833 | } |
| 834 | } |
| 835 | return nil |
| 836 | } |
| 837 | if isPrimaryRoot { |
| 838 | parent := filepath.Dir(path) |
| 839 | if filepath.Clean(parent) == filepath.Clean(folderRoot) { |
| 840 | if shouldHidePrimaryRootName(d.Name()) { |
| 841 | return filepath.SkipDir |
| 842 | } |
| 843 | } |
| 844 | } |
| 845 | if !strings.EqualFold(filepath.Ext(d.Name()), ".md") && !isExcalidrawName(d.Name()) { |
| 846 | return nil |
| 847 | } |
| 848 | files = append(files, noteFile{folder: folder, path: path}) |
| 849 | return nil |
| 850 | }) |
| 851 | if err != nil { |
| 852 | return nil, err |
| 853 | } |