editor: Highlight search results

Z-1292
This commit is contained in:
Piotr Osiewicz
2023-06-15 09:44:44 +02:00
parent 8ccb75029f
commit 86247bf657
5 changed files with 317 additions and 268 deletions
+3 -1
View File
@@ -71,7 +71,9 @@
// "never"
"show": "auto",
// Whether to show git diff indicators in the scrollbar.
"git_diff": true
"git_diff": true,
// Whether to show selections in the scrollbar.
"selections": true
},
"project_panel": {
// Whether to show the git status in the project panel.
+2
View File
@@ -15,6 +15,7 @@ pub struct EditorSettings {
pub struct Scrollbar {
pub show: ShowScrollbar,
pub git_diff: bool,
pub selections: bool,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
@@ -39,6 +40,7 @@ pub struct EditorSettingsContent {
pub struct ScrollbarContent {
pub show: Option<ShowScrollbar>,
pub git_diff: Option<bool>,
pub selections: Option<bool>,
}
impl Setting for EditorSettings {
+44 -3
View File
@@ -1008,6 +1008,7 @@ impl EditorElement {
bounds: RectF,
layout: &mut LayoutState,
cx: &mut ViewContext<Editor>,
editor: &Editor,
) {
enum ScrollbarMouseHandlers {}
if layout.mode != EditorMode::Full {
@@ -1050,9 +1051,49 @@ impl EditorElement {
background: style.track.background_color,
..Default::default()
});
let scrollbar_settings = settings::get::<EditorSettings>(cx).scrollbar;
let theme = theme::current(cx);
let scrollbar_theme = &theme.editor.scrollbar;
if layout.is_singleton && scrollbar_settings.selections {
let start_anchor = Anchor::min();
let end_anchor = Anchor::max();
for (row, _) in &editor.background_highlights_in_range(
start_anchor..end_anchor,
&layout.position_map.snapshot,
&theme,
) {
let start_display = row.start;
let end_display = row.end;
let start_y = y_for_row(start_display.row() as f32);
let mut end_y = y_for_row((end_display.row()) as f32);
if end_y - start_y < 1. {
end_y = start_y + 1.;
}
let bounds = RectF::from_points(vec2f(left, start_y), vec2f(right, end_y));
if layout.is_singleton && settings::get::<EditorSettings>(cx).scrollbar.git_diff {
let diff_style = theme::current(cx).editor.scrollbar.git.clone();
let color = scrollbar_theme.selections;
let border = Border {
width: 1.,
color: style.thumb.border.color,
overlay: false,
top: false,
right: true,
bottom: false,
left: true,
};
scene.push_quad(Quad {
bounds,
background: Some(color),
border,
corner_radius: style.thumb.corner_radius,
})
}
}
if layout.is_singleton && scrollbar_settings.git_diff {
let diff_style = scrollbar_theme.git.clone();
for hunk in layout
.position_map
.snapshot
@@ -2359,7 +2400,7 @@ impl Element<Editor> for EditorElement {
if !layout.blocks.is_empty() {
self.paint_blocks(scene, bounds, visible_bounds, layout, editor, cx);
}
self.paint_scrollbar(scene, bounds, layout, cx);
self.paint_scrollbar(scene, bounds, layout, cx, &editor);
scene.pop_layer();
scene.pop_layer();
+1
View File
@@ -700,6 +700,7 @@ pub struct Scrollbar {
pub width: f32,
pub min_height_factor: f32,
pub git: GitDiffColors,
pub selections: Color,
}
#[derive(Clone, Deserialize, Default)]
+267 -264
View File
@@ -6,273 +6,276 @@ import hoverPopover from "./hoverPopover"
import { buildSyntax } from "../theme/syntax"
export default function editor(colorScheme: ColorScheme) {
const { isLight } = colorScheme
const { isLight } = colorScheme
let layer = colorScheme.highest
let layer = colorScheme.highest
const autocompleteItem = {
cornerRadius: 6,
padding: {
bottom: 2,
left: 6,
right: 6,
top: 2,
},
}
function diagnostic(layer: Layer, styleSet: StyleSets) {
return {
textScaleFactor: 0.857,
header: {
border: border(layer, {
top: true,
}),
},
message: {
text: text(layer, "sans", styleSet, "default", { size: "sm" }),
highlightText: text(layer, "sans", styleSet, "default", {
size: "sm",
weight: "bold",
}),
},
}
}
const syntax = buildSyntax(colorScheme)
const autocompleteItem = {
cornerRadius: 6,
padding: {
bottom: 2,
left: 6,
right: 6,
top: 2,
},
}
function diagnostic(layer: Layer, styleSet: StyleSets) {
return {
textColor: syntax.primary.color,
background: background(layer),
activeLineBackground: withOpacity(background(layer, "on"), 0.75),
highlightedLineBackground: background(layer, "on"),
// Inline autocomplete suggestions, Co-pilot suggestions, etc.
suggestion: syntax.predictive,
codeActions: {
indicator: {
color: foreground(layer, "variant"),
clicked: {
color: foreground(layer, "base"),
},
hover: {
color: foreground(layer, "on"),
},
active: {
color: foreground(layer, "on"),
},
},
verticalScale: 0.55,
},
folds: {
iconMarginScale: 2.5,
foldedIcon: "icons/chevron_right_8.svg",
foldableIcon: "icons/chevron_down_8.svg",
indicator: {
color: foreground(layer, "variant"),
clicked: {
color: foreground(layer, "base"),
},
hover: {
color: foreground(layer, "on"),
},
active: {
color: foreground(layer, "on"),
},
},
ellipses: {
textColor: colorScheme.ramps.neutral(0.71).hex(),
cornerRadiusFactor: 0.15,
background: {
// Copied from hover_popover highlight
color: colorScheme.ramps.neutral(0.5).alpha(0.0).hex(),
hover: {
color: colorScheme.ramps.neutral(0.5).alpha(0.5).hex(),
},
clicked: {
color: colorScheme.ramps.neutral(0.5).alpha(0.7).hex(),
},
},
},
foldBackground: foreground(layer, "variant"),
},
diff: {
deleted: isLight
? colorScheme.ramps.red(0.5).hex()
: colorScheme.ramps.red(0.4).hex(),
modified: isLight
? colorScheme.ramps.yellow(0.5).hex()
: colorScheme.ramps.yellow(0.5).hex(),
inserted: isLight
? colorScheme.ramps.green(0.4).hex()
: colorScheme.ramps.green(0.5).hex(),
removedWidthEm: 0.275,
widthEm: 0.15,
cornerRadius: 0.05,
},
/** Highlights matching occurrences of what is under the cursor
* as well as matched brackets
*/
documentHighlightReadBackground: withOpacity(
foreground(layer, "accent"),
0.1
),
documentHighlightWriteBackground: colorScheme.ramps
.neutral(0.5)
.alpha(0.4)
.hex(), // TODO: This was blend * 2
errorColor: background(layer, "negative"),
gutterBackground: background(layer),
gutterPaddingFactor: 3.5,
lineNumber: withOpacity(foreground(layer), 0.35),
lineNumberActive: foreground(layer),
renameFade: 0.6,
unnecessaryCodeFade: 0.5,
selection: colorScheme.players[0],
whitespace: colorScheme.ramps.neutral(0.5).hex(),
guestSelections: [
colorScheme.players[1],
colorScheme.players[2],
colorScheme.players[3],
colorScheme.players[4],
colorScheme.players[5],
colorScheme.players[6],
colorScheme.players[7],
],
autocomplete: {
background: background(colorScheme.middle),
cornerRadius: 8,
padding: 4,
margin: {
left: -14,
},
border: border(colorScheme.middle),
shadow: colorScheme.popoverShadow,
matchHighlight: foreground(colorScheme.middle, "accent"),
item: autocompleteItem,
hoveredItem: {
...autocompleteItem,
matchHighlight: foreground(
colorScheme.middle,
"accent",
"hovered"
),
background: background(colorScheme.middle, "hovered"),
},
selectedItem: {
...autocompleteItem,
matchHighlight: foreground(
colorScheme.middle,
"accent",
"active"
),
background: background(colorScheme.middle, "active"),
},
},
diagnosticHeader: {
background: background(colorScheme.middle),
iconWidthFactor: 1.5,
textScaleFactor: 0.857,
border: border(colorScheme.middle, {
bottom: true,
top: true,
}),
code: {
...text(colorScheme.middle, "mono", { size: "sm" }),
margin: {
left: 10,
},
},
source: {
text: text(colorScheme.middle, "sans", {
size: "sm",
weight: "bold",
}),
},
message: {
highlightText: text(colorScheme.middle, "sans", {
size: "sm",
weight: "bold",
}),
text: text(colorScheme.middle, "sans", { size: "sm" }),
},
},
diagnosticPathHeader: {
background: background(colorScheme.middle),
textScaleFactor: 0.857,
filename: text(colorScheme.middle, "mono", { size: "sm" }),
path: {
...text(colorScheme.middle, "mono", { size: "sm" }),
margin: {
left: 12,
},
},
},
errorDiagnostic: diagnostic(colorScheme.middle, "negative"),
warningDiagnostic: diagnostic(colorScheme.middle, "warning"),
informationDiagnostic: diagnostic(colorScheme.middle, "accent"),
hintDiagnostic: diagnostic(colorScheme.middle, "warning"),
invalidErrorDiagnostic: diagnostic(colorScheme.middle, "base"),
invalidHintDiagnostic: diagnostic(colorScheme.middle, "base"),
invalidInformationDiagnostic: diagnostic(colorScheme.middle, "base"),
invalidWarningDiagnostic: diagnostic(colorScheme.middle, "base"),
hoverPopover: hoverPopover(colorScheme),
linkDefinition: {
color: syntax.linkUri.color,
underline: syntax.linkUri.underline,
},
jumpIcon: {
color: foreground(layer, "on"),
iconWidth: 20,
buttonWidth: 20,
cornerRadius: 6,
padding: {
top: 6,
bottom: 6,
left: 6,
right: 6,
},
hover: {
background: background(layer, "on", "hovered"),
},
},
scrollbar: {
width: 12,
minHeightFactor: 1.0,
track: {
border: border(layer, "variant", { left: true }),
},
thumb: {
background: withOpacity(background(layer, "inverted"), 0.3),
border: {
width: 1,
color: borderColor(layer, "variant"),
top: false,
right: true,
left: true,
bottom: false,
},
},
git: {
deleted: isLight
? withOpacity(colorScheme.ramps.red(0.5).hex(), 0.8)
: withOpacity(colorScheme.ramps.red(0.4).hex(), 0.8),
modified: isLight
? withOpacity(colorScheme.ramps.yellow(0.5).hex(), 0.8)
: withOpacity(colorScheme.ramps.yellow(0.4).hex(), 0.8),
inserted: isLight
? withOpacity(colorScheme.ramps.green(0.5).hex(), 0.8)
: withOpacity(colorScheme.ramps.green(0.4).hex(), 0.8),
},
},
compositionMark: {
underline: {
thickness: 1.0,
color: borderColor(layer),
},
},
syntax,
textScaleFactor: 0.857,
header: {
border: border(layer, {
top: true,
}),
},
message: {
text: text(layer, "sans", styleSet, "default", { size: "sm" }),
highlightText: text(layer, "sans", styleSet, "default", {
size: "sm",
weight: "bold",
}),
},
}
}
const syntax = buildSyntax(colorScheme)
return {
textColor: syntax.primary.color,
background: background(layer),
activeLineBackground: withOpacity(background(layer, "on"), 0.75),
highlightedLineBackground: background(layer, "on"),
// Inline autocomplete suggestions, Co-pilot suggestions, etc.
suggestion: syntax.predictive,
codeActions: {
indicator: {
color: foreground(layer, "variant"),
clicked: {
color: foreground(layer, "base"),
},
hover: {
color: foreground(layer, "on"),
},
active: {
color: foreground(layer, "on"),
},
},
verticalScale: 0.55,
},
folds: {
iconMarginScale: 2.5,
foldedIcon: "icons/chevron_right_8.svg",
foldableIcon: "icons/chevron_down_8.svg",
indicator: {
color: foreground(layer, "variant"),
clicked: {
color: foreground(layer, "base"),
},
hover: {
color: foreground(layer, "on"),
},
active: {
color: foreground(layer, "on"),
},
},
ellipses: {
textColor: colorScheme.ramps.neutral(0.71).hex(),
cornerRadiusFactor: 0.15,
background: {
// Copied from hover_popover highlight
color: colorScheme.ramps.neutral(0.5).alpha(0.0).hex(),
hover: {
color: colorScheme.ramps.neutral(0.5).alpha(0.5).hex(),
},
clicked: {
color: colorScheme.ramps.neutral(0.5).alpha(0.7).hex(),
},
},
},
foldBackground: foreground(layer, "variant"),
},
diff: {
deleted: isLight
? colorScheme.ramps.red(0.5).hex()
: colorScheme.ramps.red(0.4).hex(),
modified: isLight
? colorScheme.ramps.yellow(0.5).hex()
: colorScheme.ramps.yellow(0.5).hex(),
inserted: isLight
? colorScheme.ramps.green(0.4).hex()
: colorScheme.ramps.green(0.5).hex(),
removedWidthEm: 0.275,
widthEm: 0.15,
cornerRadius: 0.05,
},
/** Highlights matching occurrences of what is under the cursor
* as well as matched brackets
*/
documentHighlightReadBackground: withOpacity(
foreground(layer, "accent"),
0.1
),
documentHighlightWriteBackground: colorScheme.ramps
.neutral(0.5)
.alpha(0.4)
.hex(), // TODO: This was blend * 2
errorColor: background(layer, "negative"),
gutterBackground: background(layer),
gutterPaddingFactor: 3.5,
lineNumber: withOpacity(foreground(layer), 0.35),
lineNumberActive: foreground(layer),
renameFade: 0.6,
unnecessaryCodeFade: 0.5,
selection: colorScheme.players[0],
whitespace: colorScheme.ramps.neutral(0.5).hex(),
guestSelections: [
colorScheme.players[1],
colorScheme.players[2],
colorScheme.players[3],
colorScheme.players[4],
colorScheme.players[5],
colorScheme.players[6],
colorScheme.players[7],
],
autocomplete: {
background: background(colorScheme.middle),
cornerRadius: 8,
padding: 4,
margin: {
left: -14,
},
border: border(colorScheme.middle),
shadow: colorScheme.popoverShadow,
matchHighlight: foreground(colorScheme.middle, "accent"),
item: autocompleteItem,
hoveredItem: {
...autocompleteItem,
matchHighlight: foreground(
colorScheme.middle,
"accent",
"hovered"
),
background: background(colorScheme.middle, "hovered"),
},
selectedItem: {
...autocompleteItem,
matchHighlight: foreground(
colorScheme.middle,
"accent",
"active"
),
background: background(colorScheme.middle, "active"),
},
},
diagnosticHeader: {
background: background(colorScheme.middle),
iconWidthFactor: 1.5,
textScaleFactor: 0.857,
border: border(colorScheme.middle, {
bottom: true,
top: true,
}),
code: {
...text(colorScheme.middle, "mono", { size: "sm" }),
margin: {
left: 10,
},
},
source: {
text: text(colorScheme.middle, "sans", {
size: "sm",
weight: "bold",
}),
},
message: {
highlightText: text(colorScheme.middle, "sans", {
size: "sm",
weight: "bold",
}),
text: text(colorScheme.middle, "sans", { size: "sm" }),
},
},
diagnosticPathHeader: {
background: background(colorScheme.middle),
textScaleFactor: 0.857,
filename: text(colorScheme.middle, "mono", { size: "sm" }),
path: {
...text(colorScheme.middle, "mono", { size: "sm" }),
margin: {
left: 12,
},
},
},
errorDiagnostic: diagnostic(colorScheme.middle, "negative"),
warningDiagnostic: diagnostic(colorScheme.middle, "warning"),
informationDiagnostic: diagnostic(colorScheme.middle, "accent"),
hintDiagnostic: diagnostic(colorScheme.middle, "warning"),
invalidErrorDiagnostic: diagnostic(colorScheme.middle, "base"),
invalidHintDiagnostic: diagnostic(colorScheme.middle, "base"),
invalidInformationDiagnostic: diagnostic(colorScheme.middle, "base"),
invalidWarningDiagnostic: diagnostic(colorScheme.middle, "base"),
hoverPopover: hoverPopover(colorScheme),
linkDefinition: {
color: syntax.linkUri.color,
underline: syntax.linkUri.underline,
},
jumpIcon: {
color: foreground(layer, "on"),
iconWidth: 20,
buttonWidth: 20,
cornerRadius: 6,
padding: {
top: 6,
bottom: 6,
left: 6,
right: 6,
},
hover: {
background: background(layer, "on", "hovered"),
},
},
scrollbar: {
width: 12,
minHeightFactor: 1.0,
track: {
border: border(layer, "variant", { left: true }),
},
thumb: {
background: withOpacity(background(layer, "inverted"), 0.3),
border: {
width: 1,
color: borderColor(layer, "variant"),
top: false,
right: true,
left: true,
bottom: false,
},
},
git: {
deleted: isLight
? withOpacity(colorScheme.ramps.red(0.5).hex(), 0.8)
: withOpacity(colorScheme.ramps.red(0.4).hex(), 0.8),
modified: isLight
? withOpacity(colorScheme.ramps.yellow(0.5).hex(), 0.8)
: withOpacity(colorScheme.ramps.yellow(0.4).hex(), 0.8),
inserted: isLight
? withOpacity(colorScheme.ramps.green(0.5).hex(), 0.8)
: withOpacity(colorScheme.ramps.green(0.4).hex(), 0.8),
},
selections: isLight
? withOpacity(colorScheme.ramps.blue(0.5).hex(), 0.8)
: withOpacity(colorScheme.ramps.blue(0.4).hex(), 0.8)
},
compositionMark: {
underline: {
thickness: 1.0,
color: borderColor(layer),
},
},
syntax,
}
}