Live-update cmd-p workspace titles
This commit is contained in:
parent
c7bb691285
commit
d3a3dab74a
1 changed files with 152 additions and 41 deletions
|
|
@ -1732,12 +1732,53 @@ struct ContentView: View {
|
|||
let shortcutHint: String?
|
||||
let kindLabel: String?
|
||||
let keywords: [String]
|
||||
let liveTitleWorkspace: Workspace?
|
||||
let dismissOnRun: Bool
|
||||
let action: () -> Void
|
||||
|
||||
init(
|
||||
id: String,
|
||||
rank: Int,
|
||||
title: String,
|
||||
subtitle: String,
|
||||
shortcutHint: String?,
|
||||
kindLabel: String?,
|
||||
keywords: [String],
|
||||
liveTitleWorkspace: Workspace? = nil,
|
||||
dismissOnRun: Bool,
|
||||
action: @escaping () -> Void
|
||||
) {
|
||||
self.id = id
|
||||
self.rank = rank
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
self.shortcutHint = shortcutHint
|
||||
self.kindLabel = kindLabel
|
||||
self.keywords = keywords
|
||||
self.liveTitleWorkspace = liveTitleWorkspace
|
||||
self.dismissOnRun = dismissOnRun
|
||||
self.action = action
|
||||
}
|
||||
|
||||
var searchableTexts: [String] {
|
||||
[title, subtitle] + keywords
|
||||
}
|
||||
|
||||
func displayTitle() -> String {
|
||||
guard let liveTitleWorkspace else { return title }
|
||||
return ContentView.commandPaletteWorkspaceDisplayName(liveTitleWorkspace)
|
||||
}
|
||||
|
||||
func displayTitleMatchIndices(
|
||||
matchingQuery: String,
|
||||
fallbackIndices: Set<Int>
|
||||
) -> Set<Int> {
|
||||
guard liveTitleWorkspace != nil else { return fallbackIndices }
|
||||
return CommandPaletteFuzzyMatcher.matchCharacterIndices(
|
||||
query: matchingQuery,
|
||||
candidate: displayTitle()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private struct CommandPaletteUsageEntry: Codable, Sendable {
|
||||
|
|
@ -1991,6 +2032,39 @@ struct ContentView: View {
|
|||
var id: String { command.id }
|
||||
}
|
||||
|
||||
private struct CommandPaletteLiveWorkspaceResultLabel: View {
|
||||
@ObservedObject private var workspace: Workspace
|
||||
private let command: CommandPaletteCommand
|
||||
private let matchingQuery: String
|
||||
private let fallbackMatchIndices: Set<Int>
|
||||
private let trailingLabel: CommandPaletteTrailingLabel?
|
||||
|
||||
init(
|
||||
workspace: Workspace,
|
||||
command: CommandPaletteCommand,
|
||||
matchingQuery: String,
|
||||
fallbackMatchIndices: Set<Int>,
|
||||
trailingLabel: CommandPaletteTrailingLabel?
|
||||
) {
|
||||
_workspace = ObservedObject(wrappedValue: workspace)
|
||||
self.command = command
|
||||
self.matchingQuery = matchingQuery
|
||||
self.fallbackMatchIndices = fallbackMatchIndices
|
||||
self.trailingLabel = trailingLabel
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ContentView.commandPaletteResultLabelContent(
|
||||
title: command.displayTitle(),
|
||||
matchedIndices: command.displayTitleMatchIndices(
|
||||
matchingQuery: matchingQuery,
|
||||
fallbackIndices: fallbackMatchIndices
|
||||
),
|
||||
trailingLabel: trailingLabel
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private struct CommandPaletteResolvedSearchMatch: Sendable {
|
||||
let commandID: String
|
||||
let score: Int
|
||||
|
|
@ -3680,6 +3754,7 @@ struct ContentView: View {
|
|||
ForEach(Array(visibleResults.enumerated()), id: \.element.id) { index, result in
|
||||
let isSelected = index == selectedIndex
|
||||
let isHovered = commandPaletteHoveredResultIndex == index
|
||||
let trailingLabel = commandPaletteTrailingLabel(for: result.command)
|
||||
let rowBackground: Color = isSelected
|
||||
? cmuxAccentColor().opacity(0.12)
|
||||
: (isHovered ? Color.primary.opacity(0.08) : .clear)
|
||||
|
|
@ -3687,37 +3762,28 @@ struct ContentView: View {
|
|||
Button {
|
||||
runCommandPaletteResult(commandID: result.id)
|
||||
} label: {
|
||||
HStack(spacing: 8) {
|
||||
commandPaletteHighlightedTitleText(
|
||||
result.command.title,
|
||||
matchedIndices: result.titleMatchIndices
|
||||
)
|
||||
.font(.system(size: 13, weight: .regular))
|
||||
.lineLimit(1)
|
||||
Spacer()
|
||||
|
||||
if let trailingLabel = commandPaletteTrailingLabel(for: result.command) {
|
||||
switch trailingLabel.style {
|
||||
case .shortcut:
|
||||
Text(trailingLabel.text)
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.horizontal, 4)
|
||||
.padding(.vertical, 1)
|
||||
.background(Color.primary.opacity(0.08), in: RoundedRectangle(cornerRadius: 4, style: .continuous))
|
||||
case .kind:
|
||||
Text(trailingLabel.text)
|
||||
.font(.system(size: 11, weight: .regular))
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
Group {
|
||||
if let liveTitleWorkspace = result.command.liveTitleWorkspace {
|
||||
CommandPaletteLiveWorkspaceResultLabel(
|
||||
workspace: liveTitleWorkspace,
|
||||
command: result.command,
|
||||
matchingQuery: commandPaletteQueryForMatching,
|
||||
fallbackMatchIndices: result.titleMatchIndices,
|
||||
trailingLabel: trailingLabel
|
||||
)
|
||||
} else {
|
||||
Self.commandPaletteResultLabelContent(
|
||||
title: result.command.title,
|
||||
matchedIndices: result.titleMatchIndices,
|
||||
trailingLabel: trailingLabel
|
||||
)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 9)
|
||||
.padding(.vertical, 2)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(rowBackground)
|
||||
.contentShape(Rectangle())
|
||||
.padding(.horizontal, 9)
|
||||
.padding(.vertical, 2)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(rowBackground)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.accessibilityIdentifier("CommandPaletteResultRow.\(index)")
|
||||
|
|
@ -4814,7 +4880,7 @@ struct ContentView: View {
|
|||
return Self.commandPaletteSwitcherFingerprint(windowContexts: fingerprintContexts)
|
||||
}
|
||||
|
||||
private func commandPaletteHighlightedTitleText(_ title: String, matchedIndices: Set<Int>) -> Text {
|
||||
private static func commandPaletteHighlightedTitleText(_ title: String, matchedIndices: Set<Int>) -> Text {
|
||||
guard !matchedIndices.isEmpty else {
|
||||
return Text(title).foregroundColor(.primary)
|
||||
}
|
||||
|
|
@ -4842,6 +4908,46 @@ struct ContentView: View {
|
|||
return result
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private static func commandPaletteTrailingLabelView(_ trailingLabel: CommandPaletteTrailingLabel?) -> some View {
|
||||
if let trailingLabel {
|
||||
switch trailingLabel.style {
|
||||
case .shortcut:
|
||||
Text(trailingLabel.text)
|
||||
.font(.system(size: 11, weight: .medium))
|
||||
.foregroundStyle(.secondary)
|
||||
.padding(.horizontal, 4)
|
||||
.padding(.vertical, 1)
|
||||
.background(
|
||||
Color.primary.opacity(0.08),
|
||||
in: RoundedRectangle(cornerRadius: 4, style: .continuous)
|
||||
)
|
||||
case .kind:
|
||||
Text(trailingLabel.text)
|
||||
.font(.system(size: 11, weight: .regular))
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static func commandPaletteResultLabelContent(
|
||||
title: String,
|
||||
matchedIndices: Set<Int>,
|
||||
trailingLabel: CommandPaletteTrailingLabel?
|
||||
) -> some View {
|
||||
HStack(spacing: 8) {
|
||||
commandPaletteHighlightedTitleText(
|
||||
title,
|
||||
matchedIndices: matchedIndices
|
||||
)
|
||||
.font(.system(size: 13, weight: .regular))
|
||||
.lineLimit(1)
|
||||
Spacer()
|
||||
commandPaletteTrailingLabelView(trailingLabel)
|
||||
}
|
||||
}
|
||||
|
||||
private func commandPaletteTrailingLabel(for command: CommandPaletteCommand) -> CommandPaletteTrailingLabel? {
|
||||
if let shortcutHint = command.shortcutHint {
|
||||
return CommandPaletteTrailingLabel(text: shortcutHint, style: .shortcut)
|
||||
|
|
@ -4896,10 +5002,11 @@ struct ContentView: View {
|
|||
id: workspaceCommandId,
|
||||
rank: nextRank,
|
||||
title: workspaceName,
|
||||
subtitle: commandPaletteSwitcherSubtitle(base: String(localized: "commandPalette.switcher.workspaceLabel", defaultValue: "Workspace"), windowLabel: context.windowLabel),
|
||||
subtitle: Self.commandPaletteSwitcherSubtitle(base: String(localized: "commandPalette.switcher.workspaceLabel", defaultValue: "Workspace"), windowLabel: context.windowLabel),
|
||||
shortcutHint: nil,
|
||||
kindLabel: String(localized: "commandPalette.kind.workspace", defaultValue: "Workspace"),
|
||||
keywords: workspaceKeywords,
|
||||
liveTitleWorkspace: workspace,
|
||||
dismissOnRun: true,
|
||||
action: {
|
||||
focusCommandPaletteSwitcherTarget(
|
||||
|
|
@ -4941,7 +5048,7 @@ struct ContentView: View {
|
|||
id: surfaceCommandId,
|
||||
rank: nextRank,
|
||||
title: surfaceName,
|
||||
subtitle: commandPaletteSwitcherSubtitle(base: workspaceName, windowLabel: context.windowLabel),
|
||||
subtitle: Self.commandPaletteSwitcherSubtitle(base: workspaceName, windowLabel: context.windowLabel),
|
||||
shortcutHint: nil,
|
||||
kindLabel: surfaceKindLabel,
|
||||
keywords: surfaceKeywords,
|
||||
|
|
@ -5013,7 +5120,7 @@ struct ContentView: View {
|
|||
return contexts
|
||||
}
|
||||
|
||||
private func commandPaletteSwitcherSubtitle(base: String, windowLabel: String?) -> String {
|
||||
private static func commandPaletteSwitcherSubtitle(base: String, windowLabel: String?) -> String {
|
||||
guard let windowLabel else { return base }
|
||||
return "\(base) • \(windowLabel)"
|
||||
}
|
||||
|
|
@ -6480,7 +6587,7 @@ struct ContentView: View {
|
|||
return (workspace, panelId, panel)
|
||||
}
|
||||
|
||||
private func workspaceDisplayName(_ workspace: Workspace) -> String {
|
||||
private static func commandPaletteWorkspaceDisplayName(_ workspace: Workspace) -> String {
|
||||
let custom = workspace.customTitle?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
if !custom.isEmpty {
|
||||
return custom
|
||||
|
|
@ -6489,6 +6596,10 @@ struct ContentView: View {
|
|||
return title.isEmpty ? String(localized: "workspace.displayName.fallback", defaultValue: "Workspace") : title
|
||||
}
|
||||
|
||||
private func workspaceDisplayName(_ workspace: Workspace) -> String {
|
||||
Self.commandPaletteWorkspaceDisplayName(workspace)
|
||||
}
|
||||
|
||||
private func panelDisplayName(workspace: Workspace, panelId: UUID, fallback: String) -> String {
|
||||
let title = workspace.panelTitle(panelId: panelId)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
if !title.isEmpty {
|
||||
|
|
@ -6925,13 +7036,13 @@ struct ContentView: View {
|
|||
}
|
||||
|
||||
let rows = Array(commandPaletteVisibleResults.prefix(20)).map { result in
|
||||
CommandPaletteDebugResultRow(
|
||||
commandId: result.command.id,
|
||||
title: result.command.title,
|
||||
shortcutHint: result.command.shortcutHint,
|
||||
trailingLabel: commandPaletteTrailingLabel(for: result.command)?.text,
|
||||
score: result.score
|
||||
)
|
||||
CommandPaletteDebugResultRow(
|
||||
commandId: result.command.id,
|
||||
title: result.command.displayTitle(),
|
||||
shortcutHint: result.command.shortcutHint,
|
||||
trailingLabel: commandPaletteTrailingLabel(for: result.command)?.text,
|
||||
score: result.score
|
||||
)
|
||||
}
|
||||
|
||||
return CommandPaletteDebugSnapshot(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue