0c1047d390
- Go backend with SQLite, JWT auth, file CRUD - Vue 3 frontend with split/raw/WYSIWYG editor modes - Markdown preview (marked, GFM) - Formatting toolbar + keyboard shortcuts - File tree with search, create, delete - Light/dark theme toggle - Admin panel (user management) - Preferences (timezone, theme, default mode) - Shared documents section (placeholder) - Export: PDF, HTML, MD - Build daemon (Python, stdlib only) - Build job queue API - Docker deployment
67 lines
1.5 KiB
Go
67 lines
1.5 KiB
Go
package files
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type SearchResult struct {
|
|
Path string `json:"path"`
|
|
Snippet string `json:"snippet"`
|
|
}
|
|
|
|
// Search finds files containing the query string (case-insensitive).
|
|
func Search(dataDir, userID, query string) ([]SearchResult, error) {
|
|
root := UserDir(dataDir, userID)
|
|
query = strings.ToLower(query)
|
|
var results []SearchResult
|
|
|
|
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil || info.IsDir() {
|
|
return nil
|
|
}
|
|
rel, _ := filepath.Rel(root, path)
|
|
|
|
// Match filename
|
|
if strings.Contains(strings.ToLower(info.Name()), query) {
|
|
results = append(results, SearchResult{Path: rel, Snippet: "(filename match)"})
|
|
return nil
|
|
}
|
|
|
|
// Match content (only for .md and .txt)
|
|
ext := strings.ToLower(filepath.Ext(path))
|
|
if ext == ".md" || ext == ".txt" {
|
|
content, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
lower := strings.ToLower(string(content))
|
|
idx := strings.Index(lower, query)
|
|
if idx >= 0 {
|
|
// Extract snippet
|
|
start := idx - 40
|
|
if start < 0 {
|
|
start = 0
|
|
}
|
|
end := idx + len(query) + 40
|
|
if end > len(content) {
|
|
end = len(content)
|
|
}
|
|
snippet := string(content[start:end])
|
|
results = append(results, SearchResult{Path: rel, Snippet: snippet})
|
|
}
|
|
}
|
|
|
|
if len(results) >= 50 {
|
|
return filepath.SkipAll
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if results == nil {
|
|
results = []SearchResult{}
|
|
}
|
|
return results, nil
|
|
}
|