diff --git a/docs/docs/configuration/settings.md b/docs/docs/configuration/settings.md
index cbc55751fa..bf776e488a 100644
--- a/docs/docs/configuration/settings.md
+++ b/docs/docs/configuration/settings.md
@@ -179,8 +179,6 @@ The configuration file, `configuration.json` is in the Oni2 directory, whose loc
- `workbench.sideBar.visible` __(_bool_ default: `true`)__ - Controls the visibility of the sidebar.
-- `workbench.statusBar.visible` __(_bool_ default: `true`)__ - Controls the visibility of the status bar.
-
- `window.menuBarVisibility` __(_"visible" | "hidden"_ default: `"visible"`)__ - Controls the visibility of the menu bar.
- `window.titleBarStyle` __(_"native" | "custom"_ default: `"native"` on Windows, `"custom"` otherwise)__ - Controls whether the titlebar is custom-rendered.
@@ -191,6 +189,51 @@ The configuration file, `configuration.json` is in the Oni2 directory, whose loc
- `oni.layout.singleTabMode` __(_bool_ default: `false`)__ - When `true`, groups will only hold a single editor, and closing this editor will always close the group. It will also hide the editor tabs, and therefore essentially hide the concept of editor groups.
+#### Status Bar
+
+- `workbench.statusBar.visible` __(_bool_ default: `true`)__ - Controls the visibility of the status bar.
+
+##### Status Bar Items
+- `workbench.statusBar.items` - Controls the position and visibility of the individual items on the status bar.
+
+```JSON
+ "workbench.statusBar.items": {
+ "start": ["notificationCount", "macro", "...", "diagnosticCount", "git"],
+ "end": ["...", "lineEndings", "indentation", "fileType", "position", "modeIndicator"],
+ "showOnNotification": ["modeIndicator", "notificationCount"],
+ "hidden": [],
+ "notificationMode": "default",
+ }
+```
+
+- `start` __(_[ __items__ ]_ default: `["notificationCount", "macro", "...", "diagnosticCount", "git"]`)__ - Defines the first group of items that appear.
+
+- `end` __(_[ __items__ ]_ default: `["...", "lineEndings", "indentation", "fileType", "position", "modeIndicator"]`)__ - Defines the group of items that appears at the end of the status bar.
+
+- `showOnNotification` __(_[ __items__ ]_ default: `["notificationCount", "modeIndicator"]`)__ - Defines the group of items that are hidden by the notification popup text. Only works on `notificationMode` `default|keepPosition`
+
+- `hidden` __(_[ __items__ ]_ default: `[ ]`)__ - Defines the group of items that are always hiden.
+
+- Possible __Items__:
+ - _"notificationCount"_ - Notification Count icon and counter
+ - _"macro"_ - The vim macro indicator
+ - _"leftItems/rightItems"_ - Items that generated based on other factors, like extensions
+ - _"diagnosticCount"_ - Problem icon and counter
+ - _"git"_ - Source control information
+ - _"lineEndings"_ - Line endings information
+ - _"indentation"_ - Indentation information
+ - _"fileType"_ - File type information
+ - _"position"_ - Position information
+ - _"modeIndicator"_ - Vim mode indicator
+ - _"..."_ - The rest of the items in that group, as by the default, that are not defined in other groups
+ - _Extension Item ID_ - Any known extension item ID can be used to as an item.
+
+- `notificationMode` __(_"default | keepPosition | compact | compact+"_ default: `[ ]`)__ - Defines how the notification popup.
+ - _"default"_ - The notification popup hides the __items__ on the `showOnNotification`, and reorganizes the items to be together based on if they are on `showOnNotification`.
+ - _"keepPosition"_ - The notification popup hides the __items__ on the `showOnNotification`.
+ - _"compact"_ - The notification popups take the minimum space available, but notifications can stack up on the status bar.
+ - _"compact+"_ - The same as `compact` but notification popups do not stack up.
+
### Proxy
Onivim 2 can be configured to send requests through an HTTP/HTTPs proxy with the following configuration:
diff --git a/src/Core/ConfigurationDefaults.re b/src/Core/ConfigurationDefaults.re
index 8ee04db60a..d50debceda 100644
--- a/src/Core/ConfigurationDefaults.re
+++ b/src/Core/ConfigurationDefaults.re
@@ -36,6 +36,12 @@ let getDefaultConfigString = configName =>
"workbench.sideBar.location": "left",
"workbench.sideBar.visible": true,
"workbench.statusBar.visible": true,
+ "workbench.statusBar.items": {
+ "start": ["notificationCount", "macro", "...", "diagnosticCount", "git"],
+ "showOnNotification": ["modeIndicator", "notificationCount"],
+ "end": ["...", "lineEndings", "indentation", "fileType", "position", "modeIndicator"],
+ "hidden": [],
+ },
"workbench.tree.indent": 2,
"vim.useSystemClipboard": ["yank"]
}
diff --git a/src/Feature/Notification/Feature_Notification.re b/src/Feature/Notification/Feature_Notification.re
index 4f02fdf320..d4f9fb262b 100644
--- a/src/Feature/Notification/Feature_Notification.re
+++ b/src/Feature/Notification/Feature_Notification.re
@@ -392,6 +392,15 @@ module View = {
transform(Transform.[TranslateY(yOffset)]),
];
+ let containerCompact = (~background, ~yOffset) => [
+ position(`Relative),
+ backgroundColor(background),
+ flexDirection(`Row),
+ alignItems(`Center),
+ paddingHorizontal(10),
+ transform(Transform.[TranslateY(yOffset)]),
+ ];
+
let text = (~foreground) => [
textWrap(TextWrapping.NoWrap),
marginLeft(6),
@@ -413,6 +422,8 @@ module View = {
~background,
~foreground,
~font: UiFont.t,
+ ~onlyAnimation: bool,
+ ~compact: bool,
(),
) => {
let yOffset = model.yOffset;
@@ -433,16 +444,24 @@ module View = {
| None => React.empty
};
-
-
-
-
- ;
+ onlyAnimation
+ ?
+ :
+
+
+
+ ;
};
};
// LIST
diff --git a/src/Feature/Notification/Feature_Notification.rei b/src/Feature/Notification/Feature_Notification.rei
index cf3831465d..1a0bbf77e5 100644
--- a/src/Feature/Notification/Feature_Notification.rei
+++ b/src/Feature/Notification/Feature_Notification.rei
@@ -99,6 +99,8 @@ module View: {
~background: Color.t,
~foreground: Color.t,
~font: UiFont.t,
+ ~onlyAnimation: bool,
+ ~compact: bool,
unit
) =>
React.element(React.node);
diff --git a/src/Feature/StatusBar/Feature_StatusBar.re b/src/Feature/StatusBar/Feature_StatusBar.re
index 7e8bf2a69e..42d224fb79 100644
--- a/src/Feature/StatusBar/Feature_StatusBar.re
+++ b/src/Feature/StatusBar/Feature_StatusBar.re
@@ -40,6 +40,229 @@ module Item = {
};
};
+module ConfigurationItems = {
+ [@deriving show]
+ type notificationMode =
+ | Default
+ | KeepPosition
+ | Compact
+ | CompactPlus;
+
+ [@deriving show]
+ type t = {
+ startItems: list(string),
+ endItems: list(string),
+ hidden: list(string),
+ showOnNotification: list(string),
+ notificationMode,
+ };
+
+ let decode =
+ Json.Decode.(
+ obj(({field, _}) =>
+ {
+ startItems: field.withDefault("start", ["..."], list(string)),
+ endItems: field.withDefault("end", ["..."], list(string)),
+ hidden: field.withDefault("hidden", [], list(string)),
+ showOnNotification:
+ field.withDefault(
+ "showOnNotification",
+ ["notificationCount", "modeIndicator"],
+ list(string),
+ ),
+ notificationMode:
+ field.withDefault(
+ "notificationMode",
+ Default,
+ string
+ |> map(String.lowercase_ascii)
+ |> and_then(
+ fun
+ | "default" => succeed(Default)
+ | "keepposition" => succeed(KeepPosition)
+ | "compact" => succeed(Compact)
+ | "compact+" => succeed(CompactPlus)
+ | invalid =>
+ fail("Invalid notification mode: " ++ invalid),
+ ),
+ ),
+ }
+ )
+ );
+
+ let encode = configurationItems =>
+ Json.Encode.(
+ obj([
+ ("start", configurationItems.startItems |> list(string)),
+ (
+ "showOnNotification",
+ configurationItems.showOnNotification |> list(string),
+ ),
+ ("end", configurationItems.endItems |> list(string)),
+ ("hidden", configurationItems.hidden |> list(string)),
+ (
+ "notificationMode",
+ configurationItems.notificationMode
+ |> (
+ fun
+ | Default => "default"
+ | Compact => "compact"
+ | CompactPlus => "compact+"
+ | KeepPosition => "keepPosition"
+ )
+ |> string,
+ ),
+ ])
+ );
+
+ let codec = Config.Schema.DSL.custom(~decode, ~encode);
+
+ let startItemsDef = [
+ "notificationCount",
+ "macro",
+ "leftItems",
+ "diagnosticCount",
+ "git",
+ "notificationPopup",
+ ];
+
+ let endItemsDef = [
+ "rightItems",
+ "lineEndings",
+ "indentation",
+ "fileType",
+ "position",
+ "modeIndicator",
+ ];
+
+ let extendItem = "...";
+
+ let preProcess = (t, statusBarItems) => {
+ //Helper funcions
+ let removeFromList = (listToRemove, list) =>
+ list |> List.filter(a => !List.mem(a, listToRemove));
+
+ let process = (def, alignment, list) =>
+ list
+ |> List.map(str =>
+ if (str == extendItem) {
+ def;
+ } else {
+ [str];
+ }
+ )
+ |> List.flatten
+ |> List.map(str =>
+ (
+ str,
+ (
+ t.notificationMode == Default
+ || t.notificationMode == KeepPosition
+ )
+ && !List.mem(str, t.showOnNotification),
+ )
+ )
+ |> (
+ t.notificationMode != Default
+ ? List.fold_left(
+ (a, item) => {
+ let (toAdd, notificationToAdd) = item;
+ let (head, notification) = a |> List.hd;
+
+ notificationToAdd == notification
+ ? [(head @ [toAdd], notification)] @ (a |> List.tl)
+ : [([toAdd], notificationToAdd)] @ a;
+ },
+ [([], false)],
+ )
+ //Merge all Items that are to be hidden notificaion and those that arent into
+ //separate positions
+ : List.fold_left(
+ (a, item) => {
+ let (toAdd, notificationToAdd) = item;
+ let (head, _) = a |> List.hd;
+ let (tail, _) = a |> List.tl |> List.hd;
+
+ let isRight = alignment == Right;
+
+ if (isRight) {
+ !notificationToAdd
+ ? [(head, true), (tail @ [toAdd], false)]
+ : [(head @ [toAdd], true), (tail, false)];
+ } else {
+ notificationToAdd
+ ? [(head, false), (tail @ [toAdd], true)]
+ : [(head @ [toAdd], false), (tail, true)];
+ };
+ },
+ [([], false), ([], false)],
+ )
+ );
+
+ let allItems =
+ t.startItems @ t.endItems |> List.filter(a => a != extendItem);
+
+ //Get if `...` if its, on the rigth and left
+ let extendStart = List.mem(extendItem, t.startItems);
+ let extendEnd = List.mem(extendItem, t.endItems);
+
+ /*
+ if x has `...` and !x doesn't then add them all
+ else if x can extended then do
+ else then no default
+ */
+ let startItemsPDef =
+ (
+ if (extendStart && !extendEnd) {
+ endItemsDef @ startItemsDef;
+ } else if (extendStart) {
+ startItemsDef;
+ } else {
+ [];
+ }
+ )
+ |> removeFromList(allItems @ t.hidden);
+
+ let endItemsPDef =
+ (
+ if (extendEnd && !extendStart) {
+ startItemsDef @ endItemsDef;
+ } else if (extendEnd) {
+ endItemsDef;
+ } else {
+ [];
+ }
+ )
+ |> removeFromList(allItems @ t.hidden);
+
+ let getItemsFromAlign = align =>
+ statusBarItems
+ |> List.filter((item: Item.t) =>
+ item.alignment == align
+ && !(
+ (
+ switch (item.command) {
+ | Some(command) => List.mem(command, allItems @ t.hidden)
+ | None => false
+ }
+ )
+ || List.mem(item.id, allItems @ t.hidden)
+ )
+ );
+
+ (
+ process(startItemsPDef, Right, t.startItems),
+ process(endItemsPDef, Left, t.endItems),
+ List.mem("center", t.showOnNotification)
+ || t.notificationMode != Default
+ && t.notificationMode != KeepPosition,
+ getItemsFromAlign(Right),
+ getItemsFromAlign(Left),
+ t.notificationMode,
+ );
+ };
+};
+
// MSG
[@deriving show]
@@ -198,7 +421,8 @@ module Styles = {
transform(Transform.[TranslateY(yOffset)]),
];
- let sectionGroup = [
+ let sectionGroup = background => [
+ backgroundColor(background),
position(`Relative),
flexDirection(`Row),
justifyContent(`SpaceBetween),
@@ -236,8 +460,8 @@ let positionToString =
)
| None => "";
-let sectionGroup = (~children, ()) =>
- children ;
+let sectionGroup = (~background, ~children, ()) =>
+ children ;
let section = (~children=React.empty, ~align, ()) =>
children ;
@@ -396,6 +620,7 @@ module View = {
~theme,
~dispatch,
~workingDirectory: string,
+ ~items: ConfigurationItems.t,
(),
) => {
let activeNotifications = Feature_Notification.active(notifications);
@@ -405,6 +630,8 @@ module View = {
Feature_Notification.statusBarForeground(~theme, notifications);
let defaultForeground = Colors.StatusBar.foreground.from(theme);
+ let defaultBackground =
+ Feature_Theme.Colors.StatusBar.background.from(theme);
let yOffset = 0.;
@@ -444,21 +671,6 @@ module View = {
- viewOrTooltip
;
};
- let leftItems =
- statusBar.items
- |> List.filter((item: Item.t) => item.alignment == Left)
- |> List.map(
- ({command, label, color, tooltip, backgroundColor, _}: Item.t) =>
- toStatusBarElement(
- ~command?,
- ~backgroundColor?,
- ~color?,
- ~tooltip?,
- label,
- )
- )
- |> React.listToElement;
-
let scmItems =
scm
|> Feature_SCM.statusBarCommands(~workingDirectory)
@@ -471,14 +683,6 @@ module View = {
)
|> React.listToElement;
- let rightItems =
- statusBar.items
- |> List.filter((item: Item.t) => item.alignment == Right)
- |> List.map(({command, label, color, tooltip, _}: Item.t) =>
- toStatusBarElement(~command?, ~color?, ~tooltip?, label)
- )
- |> React.listToElement;
-
let indentation = () => {
let text = indentationSettings |> indentationToString;
@@ -553,50 +757,153 @@ module View = {
;
};
- let notificationPopups = () =>
+ let macroElement =
+ recordingMacro
+ |> Option.map(register => )
+ |> Option.value(~default=React.empty);
+
+ let (
+ startItems,
+ endItems,
+ center,
+ rightItems,
+ leftItems,
+ notificationMode,
+ ) =
+ ConfigurationItems.preProcess(items, statusBar.items);
+
+ let notificationPopups = (~onlyAnimation, ~compact, ()) =>
activeNotifications
|> List.rev
- |> List.map(model =>
-
+ |> (
+ list =>
+ (
+ notificationMode == CompactPlus && list |> List.length > 0
+ ? [list |> List.hd] : list
+ )
+ |> List.map(model =>
+
+ )
+ |> React.listToElement
+ );
+
+ let rightItems =
+ rightItems
+ |> List.map(({command, label, color, tooltip, _}: Item.t) =>
+ toStatusBarElement(~command?, ~color?, ~tooltip?, label)
)
|> React.listToElement;
- let macroElement =
- recordingMacro
- |> Option.map(register => )
- |> Option.value(~default=React.empty);
+ let leftItems =
+ leftItems
+ |> List.map(({command, label, color, tooltip, _}: Item.t) =>
+ toStatusBarElement(~command?, ~color?, ~tooltip?, label)
+ )
+ |> React.listToElement;
-
-
-
-
-
-
-
-
-
-
-
-
+ let itemsToElement = list =>
+ list
+ |> List.rev_map(item => {
+ let (list, noti) = item;
+ let onlyAnimation = !List.mem("notificationPopup", list);
+ let list =
+ list
+ |> List.map(str =>
+ switch (str) {
+ | "modeIndicator" =>
+
+ | "notificationCount" =>
+
+ | "diagnosticCount" =>
+
+ | "lineEndings" =>
+ | "indentation" =>
+ | "fileType" =>
+ | "position" =>
+ | "macro" => macroElement
+ | "leftItems" => leftItems
+ | "git" => scmItems
+ | "rightItems" => rightItems
+ | "notificationPopup" =>
+ notificationMode != Default
+ ?
+ : React.empty
+ | str =>
+ statusBar.items
+ |> List.filter((item: Item.t) =>
+ item.id == str
+ || (
+ switch (item.command) {
+ | Some(command) => command == str
+ | None => false
+ }
+ )
+ )
+ |> List.map(
+ ({command, label, color, tooltip, _}: Item.t) =>
+ toStatusBarElement(
+ ~command?,
+ ~color?,
+ ~tooltip?,
+ label,
+ )
+ )
+ |> React.listToElement
+ }
+ );
+ let reactList = list |> React.listToElement;
+
+ let count =
+ list
+ |> List.fold_left((a, b) => b != React.empty ? a + 1 : a, 0);
+
+ if (noti && count > 0) {
+
+
+
+ ;
+ } else if (noti) {
+
+
+ ;
+ } else {
+
+
+ ;
+ };
+ })
+ |> React.listToElement;
+
+ let startItems = startItems |> itemsToElement;
+ let endItems = endItems |> itemsToElement;
+ let center =
+ center
+ ? React.empty : ;
+ //Feature_Theme.Colors.StatusBar.background.from(theme)
+
+
+
+
;
};
};
@@ -604,8 +911,20 @@ module View = {
module Configuration = {
open Config.Schema;
let visible = setting("workbench.statusBar.visible", bool, ~default=true);
+ let items =
+ setting(
+ "workbench.statusBar.items",
+ ConfigurationItems.codec,
+ ~default={
+ startItems: ["..."],
+ endItems: ["..."],
+ showOnNotification: ["notificationCount", "modeIndicator"],
+ hidden: [],
+ notificationMode: Default,
+ },
+ );
};
module Contributions = {
- let configuration = Configuration.[visible.spec];
+ let configuration = Configuration.[visible.spec, items.spec];
};
diff --git a/src/Feature/StatusBar/Feature_StatusBar.rei b/src/Feature/StatusBar/Feature_StatusBar.rei
index ac4a60bb43..432777d98d 100644
--- a/src/Feature/StatusBar/Feature_StatusBar.rei
+++ b/src/Feature/StatusBar/Feature_StatusBar.rei
@@ -17,6 +17,21 @@ module Item: {
t;
};
+module ConfigurationItems: {
+ type notificationMode =
+ | Default
+ | KeepPosition
+ | Compact
+ | CompactPlus;
+
+ type t = {
+ startItems: list(string),
+ endItems: list(string),
+ hidden: list(string),
+ showOnNotification: list(string),
+ notificationMode,
+ };
+};
// MODEL
[@deriving show]
@@ -62,6 +77,7 @@ module View: {
~theme: ColorTheme.Colors.t,
~dispatch: msg => unit,
~workingDirectory: string,
+ ~items: ConfigurationItems.t,
unit
) =>
Revery.UI.element;
@@ -69,7 +85,10 @@ module View: {
// CONFIGURATION
-module Configuration: {let visible: Config.Schema.setting(bool);};
+module Configuration: {
+ let visible: Config.Schema.setting(bool);
+ let items: Config.Schema.setting(ConfigurationItems.t);
+};
// CONTRIBUTIONS
diff --git a/src/UI/Root.re b/src/UI/Root.re
index 69b2030f98..85d4ac7cfb 100644
--- a/src/UI/Root.re
+++ b/src/UI/Root.re
@@ -162,6 +162,7 @@ let make = (~dispatch, ~state: State.t, ()) => {
workingDirectory={Feature_Workspace.workingDirectory(
state.workspace,
)}
+ items={Feature_StatusBar.Configuration.items.get(config)}
/>
;
} else {