Skip to content

Commit

Permalink
feat(ux/#528.1): Initial vim-navigable list component (#2476)
Browse files Browse the repository at this point in the history
This is another step towards #528 - this creates a vim-navigable list component to be reused across portions of our UI.

In this PR, it's hooked up to search:
![2020-09-18 14 23 00](https://user-images.githubusercontent.com/13532591/93646232-aecb1700-f9ba-11ea-8fce-dfa7dd04cef2.gif)

__TODO - Blocking check-in:__ 
- [x] Fix diagnostics pane (requires #2466, #2478 )
- [x] Remove 'LocationList', which is replaced by the vim-navigable list + `LocationListItem`

Next steps:
- Hook up the vim-navigable-list to SCM
- Hook up the vim-navigable-list to Extensions
- Hook up the vim-navigable-list to Notifications (requires #2466)
- Create a vim-navigable-tree, to be used with the file explorer - and can address #528 
- Hook up search `/` / `?`
- Improve the UX of the search pane, so that the results are more visible - it's not very useful in the current form.
  • Loading branch information
bryphe authored Sep 19, 2020
1 parent dd0613f commit 41e4287
Show file tree
Hide file tree
Showing 27 changed files with 1,284 additions and 401 deletions.
225 changes: 0 additions & 225 deletions src/Components/LocationList.re

This file was deleted.

151 changes: 151 additions & 0 deletions src/Components/LocationListItem.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
open EditorCoreTypes;
open Revery;
open Revery.UI;
open Oni_Core;
open Utility;

module Log = (val Log.withNamespace("Oni2.UI.LocationListItem"));

module Colors = Feature_Theme.Colors;

type t = {
file: string,
location: CharacterPosition.t,
text: string,
highlight: option((Index.t, Index.t)),
};

module Styles = {
open Style;

let clickable = [cursor(Revery.MouseCursors.pointer)];

let result = (~theme, ~isHovered) => [
flexDirection(`Row),
overflow(`Hidden),
paddingVertical(4),
paddingHorizontal(8),
backgroundColor(
isHovered
? Colors.Menu.selectionBackground.from(theme)
: Revery.Colors.transparentWhite,
),
];

let locationText = (~theme) => [
color(Colors.EditorLineNumber.activeForeground.from(theme)),
textWrap(TextWrapping.NoWrap),
];

let snippet = (~theme, ~isHighlighted) => [
color(
isHighlighted
? Colors.Oni.normalModeBackground.from(theme)
: Colors.foreground.from(theme),
),
textWrap(TextWrapping.NoWrap),
];
};

module View = {
let make =
(
~theme,
~uiFont: UiFont.t,
~editorFont: Service_Font.font,
~width,
~isHovered,
~item,
~workingDirectory,
(),
) => {
// let workingDirectory = Rench.Environment.getWorkingDirectory(); // TODO: This should be workspace-relative

let locationText =
Printf.sprintf(
"%s:%n - ",
Path.toRelative(~base=workingDirectory, item.file),
EditorCoreTypes.LineNumber.toOneBased(item.location.line),
);

let locationWidth = {
Revery.Draw.Text.dimensions(
~smoothing=Revery.Font.Smoothing.default,
~fontSize=uiFont.size,
~fontFamily=uiFont.family,
~fontWeight=Normal,
locationText,
).
width;
};

let location = () =>
<Text
style={Styles.locationText(~theme)}
fontFamily={uiFont.family}
fontSize={uiFont.size}
text=locationText
/>;

let content = () => {
let unstyled = (~text, ()) =>
<Text
style={Styles.snippet(~theme, ~isHighlighted=false)}
fontFamily={editorFont.fontFamily}
fontSize={editorFont.fontSize}
text
/>;

let highlighted = (~text, ()) =>
<Text
style={Styles.snippet(~theme, ~isHighlighted=true)}
fontFamily={editorFont.fontFamily}
fontSize={editorFont.fontSize}
text
/>;

switch (item.highlight) {
| Some((indexStart, indexEnd)) =>
let availableWidth = float(width) -. locationWidth;
let maxLength = int_of_float(availableWidth /. editorFont.spaceWidth);
let charStart = Index.toZeroBased(indexStart);
let charEnd = Index.toZeroBased(indexEnd);

try({
let (text, charStart, charEnd) =
StringEx.extractSnippet(
~maxLength,
~charStart,
~charEnd,
item.text,
);
let before = String.sub(text, 0, charStart);
let matchedText = String.sub(text, charStart, charEnd - charStart);
let after =
String.sub(text, charEnd, String.length(text) - charEnd);

<View style=Style.[flexDirection(`Row)]>
<unstyled text=before />
<highlighted text=matchedText />
<unstyled text={StringEx.trimRight(after)} />
</View>;
}) {
| Invalid_argument(message) =>
// TODO: This shouldn't happen, but you never know. Consider a sane implementation of `String.sub` instead, to avoid this
Log.errorf(m =>
m("\"%s\" - (%n, %n)\n%!", message, charStart, charEnd)
);
<unstyled text={item.text} />;
};
| None => <unstyled text={item.text} />
};
};

<View style=Styles.clickable>
<View style={Styles.result(~theme, ~isHovered)}>
<location />
<content />
</View>
</View>;
};
};
Loading

0 comments on commit 41e4287

Please sign in to comment.