Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File Explorer Keyboard Navigation - Part 1 #1086

Merged
30 changes: 30 additions & 0 deletions src/Core/Utility.re
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,24 @@ module RangeUtil = {
};
};

module ArrayEx = {
exception Found(int);

let findIndex = (predicate, array) =>
try(
{
for (i in 0 to Array.length(array) - 1) {
if (predicate(array[i])) {
raise(Found(i));
};
};
None;
}
) {
| Found(i) => Some(i)
};
};

// TODO: Remove after 4.08 upgrade
module List = {
include List;
Expand Down Expand Up @@ -683,3 +701,15 @@ module ChunkyQueue: {
let toList = ({front, rear, _}) =>
front @ (Queue.toList(rear) |> List.concat);
};

module Path = {
// Not very robust path-handling utilities.
// TODO: Make good

let toRelative = (~base, path) => {
let base = base == "/" ? base : base ++ Filename.dir_sep;
Str.replace_first(Str.regexp_string(base), "", path);
};

let explode = String.split_on_char(Filename.dir_sep.[0]);
};
Comment on lines +705 to +715
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could consider using the Fp/Path library from reason-native: https://github.com/facebookexperimental/reason-native/tree/master/src/fp
(if it makes sense)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that looks pretty good. It doesn't seem to have any way of destructuring it like explode though. But we could contribute that.

34 changes: 14 additions & 20 deletions src/Model/FileExplorer.re
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
open Revery;
open Oni_Core;
open Oni_Extensions;

type t = {
tree: option(FsTreeNode.t),
isOpen: bool,
scrollOffset: [ | `Start(float) | `Middle(float)],
focus: option(string) // path
active: option(string), // path
focus: option(string) // node id
};

[@deriving show({with_path: false})]
type action =
| TreeLoaded([@opaque] FsTreeNode.t)
| NodeLoaded(int, [@opaque] FsTreeNode.t)
| FocusNodeLoaded(int, [@opaque] FsTreeNode.t)
| NodeLoaded(string, [@opaque] FsTreeNode.t)
| FocusNodeLoaded(string, [@opaque] FsTreeNode.t)
| NodeClicked([@opaque] FsTreeNode.t)
| ScrollOffsetChanged([ | `Start(float) | `Middle(float)]);

module ExplorerId =
UniqueId.Make({});
| ScrollOffsetChanged([ | `Start(float) | `Middle(float)])
| Select
| FocusPrev
| FocusNext;

let getFileIcon = (languageInfo, iconTheme, filePath) => {
let fileIcon =
Expand Down Expand Up @@ -79,7 +79,6 @@ let getFilesAndFolders = (~ignored, cwd, getIcon) => {
let rec getDirContent = (~loadChildren=false, cwd) => {
let toFsTreeNode = file => {
let path = Filename.concat(cwd, file);
let id = ExplorerId.getUniqueId();

if (isDirectory(path)) {
let%lwt children =
Expand All @@ -94,10 +93,11 @@ let getFilesAndFolders = (~ignored, cwd, getIcon) => {
Lwt.return([]);
};

FsTreeNode.directory(path, ~id, ~icon=getIcon(path), ~children)
|> Lwt.return;
Lwt.return(
FsTreeNode.directory(path, ~icon=getIcon(path), ~children),
);
} else {
FsTreeNode.file(path, ~id, ~icon=getIcon(path)) |> Lwt.return;
FsTreeNode.file(path, ~icon=getIcon(path)) |> Lwt.return;
};
};

Expand All @@ -116,25 +116,19 @@ let getFilesAndFolders = (~ignored, cwd, getIcon) => {
};

let getDirectoryTree = (cwd, languageInfo, iconTheme, ignored) => {
let id = ExplorerId.getUniqueId();
let getIcon = getFileIcon(languageInfo, iconTheme);
let children =
getFilesAndFolders(~ignored, cwd, getIcon)
|> Lwt_main.run
|> List.sort(sortByLoweredDisplayName);

FsTreeNode.directory(
cwd,
~id,
~icon=getIcon(cwd),
~children,
~isOpen=true,
);
FsTreeNode.directory(cwd, ~icon=getIcon(cwd), ~children, ~isOpen=true);
};

let initial = {
tree: None,
isOpen: true,
scrollOffset: `Start(0.),
active: None,
focus: None,
};
12 changes: 8 additions & 4 deletions src/Model/FileExplorer.rei
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ type t = {
tree: option(FsTreeNode.t),
isOpen: bool,
scrollOffset: [ | `Start(float) | `Middle(float)],
focus: option(string) // path
active: option(string), // path
focus: option(string) // node id
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: path, not id

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be one nice thing about using a path library like Path/fp - we could have a type for it

};

[@deriving show]
type action =
| TreeLoaded([@opaque] FsTreeNode.t)
| NodeLoaded(int, [@opaque] FsTreeNode.t)
| FocusNodeLoaded(int, [@opaque] FsTreeNode.t)
| NodeLoaded(string, [@opaque] FsTreeNode.t)
| FocusNodeLoaded(string, [@opaque] FsTreeNode.t)
| NodeClicked([@opaque] FsTreeNode.t)
| ScrollOffsetChanged([ | `Start(float) | `Middle(float)]);
| ScrollOffsetChanged([ | `Start(float) | `Middle(float)])
| Select
| FocusPrev
| FocusNext;

let initial: t;

Expand Down
Loading