gitbay/Views/Discovery/GrepView.swift
57 lines · 2144 bytes
1import SwiftUI
2
3/// Server-side git grep over a repository's files.
4struct GrepView: View {
5
6 @State private var model: GrepViewModel
7 @State private var query = ""
8
9 init(client: GitbayClient, repo: String) {
10 _model = State(initialValue: GrepViewModel(client: client, repoPath: repo))
11 }
12
13 var body: some View {
14 List {
15 ForEach(model.byFile, id: \.file) { group in
16 Section {
17 ForEach(group.matches) { match in
18 NavigationLink(value: RepoRoute.file(
19 repo: model.repoPath, path: match.path, ref: nil
20 )) {
21 HStack(alignment: .firstTextBaseline, spacing: 8) {
22 Text(String(match.line))
23 .font(.gbMono(.caption))
24 .foregroundStyle(.tertiary)
25 .frame(minWidth: 32, alignment: .trailing)
26 Text(match.text.trimmingCharacters(in: .whitespaces))
27 .font(.gbMono(.caption))
28 .lineLimit(2)
29 }
30 }
31 }
32 } header: {
33 Text(group.file)
34 .font(.gbMono(.caption))
35 .textCase(nil)
36 }
37 }
38 }
39 .overlay {
40 if let state = model.state {
41 LoadStateOverlay(state: state)
42 } else {
43 ContentUnavailableView {
44 Label("Search in files", systemImage: "text.magnifyingglass")
45 } description: {
46 Text("Literal, case-insensitive, over the default branch — git grep, server-side.")
47 }
48 }
49 }
50 .searchable(text: $query, prompt: "Search file contents")
51 .onSubmit(of: .search) {
52 Task { await model.search(query) }
53 }
54 .navigationTitle("Grep")
55 .navigationBarTitleDisplayMode(.inline)
56 }
57}