Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,15 +160,34 @@ Task Monitor stores configuration and log files in the following system director
## Theme Files

Theme files control the color palette behavior for color desaturation, background opacity, and the colors applied to the TUI screen elements.
There a number of default themes that are pre-loaded when Task Monitor starts. These themes are kept in .ini files and can be customized as required. Additionally, new theme
files can be authored and copied to the theme files directory and will automatically be available next time Task Monitor starts.
Theme files use the ini file format (see example below). Any modifications to default/shjpped theme files will be reset automatically when
taskmon updates. To create new, custom themes, simply copy an existing theme and modify the settings as required.
These files will automatically be available next time Task Monitor starts.

Below is an example theme file:
```
;=============================================================================
; Task Monitor (taskmon) - Built-in Theme
;=============================================================================
; IMPORTANT:
; Any modifications to default/shipped theme files will be reset automatically
; when taskmon runs or updates.
;
; How to create a custom theme:
; Step 1: Copy this file to a new name (e.g. "Tokyo Night Custom.theme").
; Step 2: Rename the header "[Tokyo Night]" to "[Tokyo Night Custom]".
; Step 3: Customize color hex values (#RRGGBB).
;=============================================================================

[Dracula Official]
colour-mode=indexed

background=transparent
background-highlight=#3b5070

chart-border=#a9b1d6
chart-y-axis=#9ece6a

col-cmd-normal-user-space=#50fa7b
col-cmd-low-priority=#0000FF
col-cmd-high-cpu=#ff79c6
Expand All @@ -178,20 +197,27 @@ col-user-current-non-root=#f8f8f2
col-user-other-non-root=#f1fa8c
col-user-system=#ff79c6
col-user-root=#50fa7b

command-foreground=#bd93f9
command-background=#282a36

delta-highlight-colour=#ffb86c

error=#db61a2

foreground=#f8f8f2
foreground-highlight=#ffb86c

menubar-foreground=#f1fa8c
menubar-background=#282a36

range-high-background=#bd93f9
range-low-background=#f1fa8c
range-mid-background=#ffb86c
range-high-foreground=#000000
range-low-foreground=#000000
range-mid-foreground=#000000

header-background=#282a36
header-foreground=#f1fa8c
```
Expand All @@ -202,6 +228,10 @@ header-foreground=#f1fa8c
| `colour-mode=indexed` | `Indexed` means use the color palette that supports color desaturation on modern terminals. `Truecolour` prevents desaturation (by emitting ARGB) escape codes. `Auto` detects terminal support. |
| `background=transparent` | `transparent` honors background color opacity settings in the terminal. Otherwise specify a custom background color to override the terminal default. |
| `background-highlight=#3b5070` | Row selection background color in a list. |

| `chart-border=#f8f8f2` | Chart border color. |
| `chart-y-axis=#50fa7b` | Text color for chart Y-axis scale. |

| `col-cmd-normal-user-space=#50fa7b` | Text color for user-mode applications. |
| `col-cmd-low-priority=#0000FF` | Text color for applications running at a low priority. |
| `col-cmd-high-cpu=#ff79c6` | Text color for a process running at high CPU%. |
Expand Down Expand Up @@ -232,7 +262,7 @@ Note: ```colour-mode``` can be temporarily overridden for ALL theme files by set

## Layout Files

Layout files control the number, sequence, rows and columns of the chart layouts on the main process screen. There a number of default layouts that are pre-loaded when Task Monitor starts.
Layout files control the number, sequence, rows and columns of the chart layouts on the main process screen. There are a number of default layouts that are pre-loaded when Task Monitor starts.
These layouts are kept in .ini files and can be customized as required. Additionally, new layout
files can be authored and copied to the layout files directory and will automatically be available next time Task Monitor starts.

Expand Down Expand Up @@ -341,7 +371,7 @@ or behaviors can't be reproduced in IDE consoles, or are specific to the termina
### Writing Code / Project Structure

* **Interop Layer**: All native OS calls are isolated in `Task.Monitor.Interop.Mach` (macOS) and `Task.Monitor.Interop.Win32` (Windows). If you need to add a new OS metric, define the P/Invoke signatures here.
* **System Abstraction**: The `Task.Monitor.System` project consumes the Interop layer to provide cross-platform models (e.g., `SystemStatistics`, `ProcessInfo`).
* **System Abstraction**: The `Task.Monitor.System` project consumes the Interop layer to provide cross-platform models (e.g., `SystemStatistics`, `ProcessInfo`). The TUI rendering framework also lives in this library.
* **UI/CLI**: The `taskmon` project contains the main application logic, rendering, and terminal UI layouts.
* **Themes/Layouts**: Custom terminal themes and layouts are stored as embedded resources in `src/taskmon/Assets/`.
* **Test Projects**: There is a matching test project for every application project.
Expand Down
2 changes: 1 addition & 1 deletion docs/RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,4 @@ brew install --build-from-source homebrew-tap/Formula/taskmon.rb

Releases are tracked in:
- [GitHub Releases](https://github.com/jchas2/taskmon/releases)
- [Homebrew Formula](https://github.com/jchas2/homebrew-taskmon/commits/main/Formula/taskmgr.rb)
- [Homebrew Formula](https://github.com/jchas2/homebrew-taskmon/commits/main/Formula/taskmon.rb)
12 changes: 12 additions & 0 deletions src/Task.Monitor.Internal.Abstractions/FileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,18 @@ public sealed partial class FileSystem : IFileSystem

public bool FileExists(string? path) => File.Exists(path);

public long GetFileLength(string path)
{
try {
FileInfo finfo = new(path);
return finfo.Length;
}
catch (Exception ex) {
ExceptionHelper.LogException(ex, $"Error on GetFileLength '{path}'");
return -1;
}
}

public string[] GetFiles(string path)
{
try {
Expand Down
1 change: 1 addition & 0 deletions src/Task.Monitor.Internal.Abstractions/IFileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public interface IFileSystem
public bool TryCreateDirectory(string path);
public bool DirectoryExists(string? path);
public bool FileExists(string? path);
public long GetFileLength(string path);
string[] GetFiles(string path);
public string ReadAllText(string path);
public void WriteAllText(string path, string? contents);
Expand Down
31 changes: 20 additions & 11 deletions src/Task.Monitor.System/Controls/Chart/Chart.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Buffers.Text;
using System.Drawing;
using Task.Monitor.Cli.Utils;

Expand Down Expand Up @@ -67,19 +68,21 @@ private void AddInternal(double value)
}

public bool AutoScale { get; set; } = true;

public Func<double, string>? CustomYAxisScaleFormatter { get; set; }

private int DataCapacity => Math.Max(0, Width - 2 - ScaleWidth);

public Color BorderColour { get; set; } = ConsolePalette.White;

public Color ColourHigh { get; set; } = ConsolePalette.Red;

public Color ColourLow { get; set; } = ConsolePalette.DarkGreen;

public Color ColourMid { get; set; } = ConsolePalette.Yellow;

public Func<double, string>? CustomYAxisScaleFormatter { get; set; }

private double DataAt(int i) => data[(dataHead + i) % data.Length];

private int DataCapacity => Math.Max(0, Width - 2 - ScaleWidth);

public static string FormatYScalePercentage(double value)
{
int pct = (int)Math.Round(value * 100.0);
Expand Down Expand Up @@ -153,14 +156,14 @@ protected override void OnDraw()

frame.Clear();
frame.MoveTo(X, Y);
frame.SetColour(ForegroundColour, BackgroundColour);
frame.SetColour(BorderColour, BackgroundColour);
frame.Append('\u256D');
frame.Append('\u2500', totalInnerWidth);
frame.Append('\u256E');

for (int row = 0; row < chartHeight; row++) {
frame.MoveTo(X, Y + 1 + row);
frame.SetColour(ForegroundColour, BackgroundColour);
frame.SetColour(BorderColour, BackgroundColour);
frame.Append('\u2502');

int rowFromBottom = chartHeight - 1 - row;
Expand All @@ -170,7 +173,7 @@ protected override void OnDraw()
int sampleIndex = sampleCount - chartWidth + col;

if (sampleIndex < 0) {
frame.SetColour(ForegroundColour, BackgroundColour);
frame.SetColour(BorderColour, BackgroundColour);
frame.Append('\u2800');
continue;
}
Expand Down Expand Up @@ -215,7 +218,7 @@ protected override void OnDraw()
SetCellColour(chartColour);
}
else {
frame.SetColour(ForegroundColour, BackgroundColour);
frame.SetColour(BorderColour, BackgroundColour);
ch = '\u2800';
}

Expand All @@ -224,7 +227,7 @@ protected override void OnDraw()

if (showScale) {
bool isIndexRow = (row % 2 == 0) || (row == chartHeight - 1);
frame.SetColour(ForegroundColour, BackgroundColour);
frame.SetColour(BorderColour, BackgroundColour);

if (isIndexRow) {
double ratio = chartHeight > 1 ? (double)rowFromBottom / (chartHeight - 1) : 0.0;
Expand All @@ -235,7 +238,9 @@ protected override void OnDraw()
formatted = formatted[..scaleWidth];
}

frame.SetColour(YAxisColour, BackgroundColour);
frame.Append(formatted.PadLeft(scaleWidth));
frame.SetColour(BorderColour, BackgroundColour);
frame.Append('\u2524');
}
else {
Expand All @@ -244,13 +249,12 @@ protected override void OnDraw()
}
}
else {
frame.SetColour(ForegroundColour, BackgroundColour);
frame.SetColour(BorderColour, BackgroundColour);
frame.Append('\u2502');
}
}

frame.MoveTo(X, Y + Height - 1);
frame.SetColour(ForegroundColour, BackgroundColour);

string label = string.IsNullOrEmpty(LabelSeries)
? Text
Expand All @@ -261,9 +265,12 @@ protected override void OnDraw()
int leftDashes = (totalInnerWidth - labelLen) / 2;
int rightDashes = totalInnerWidth - labelLen - leftDashes;

frame.SetColour(BorderColour, BackgroundColour);
frame.Append('\u2570');
frame.Append('\u2500', leftDashes);
frame.SetColour(ForegroundColour, BackgroundColour);
frame.Append(labelLen < labelPadded.Length ? labelPadded[..labelLen] : labelPadded);
frame.SetColour(BorderColour, BackgroundColour);
frame.Append('\u2500', rightDashes);
frame.Append('\u256F');

Expand Down Expand Up @@ -317,4 +324,6 @@ public bool ShowYAxisScale
}

public string Text { get; set; } = string.Empty;

public Color YAxisColour { get; set; } = ConsolePalette.White;
}
17 changes: 16 additions & 1 deletion src/taskmon/Assets/Themes/Alien Blood.theme
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
[Alien Blood]
;=============================================================================
; Task Monitor (taskmon) - Built-in Theme
;=============================================================================
; IMPORTANT:
; Any modifications to default/shipped theme files will be reset automatically
; when taskmon runs or updates.
;
; How to create a custom theme:
; Step 1: Copy this file to a new name (e.g. "Tokyo Night Custom.theme").
; Step 2: Rename the header "[Tokyo Night]" to "[Tokyo Night Custom]".
; Step 3: Customize color hex values (#RRGGBB).
;=============================================================================
[Alien Blood]
colour-mode=truecolour

background=#0f1610
background-highlight=#1d4125

chart-border=#717f24
chart-y-axis=#327f77

col-cmd-normal-user-space=#327f77
col-cmd-low-priority=#10b981
col-cmd-high-cpu=#b082d1
Expand Down
17 changes: 16 additions & 1 deletion src/taskmon/Assets/Themes/Ayu.theme
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
[Ayu]
;=============================================================================
; Task Monitor (taskmon) - Built-in Theme
;=============================================================================
; IMPORTANT:
; Any modifications to default/shipped theme files will be reset automatically
; when taskmon runs or updates.
;
; How to create a custom theme:
; Step 1: Copy this file to a new name (e.g. "Tokyo Night Custom.theme").
; Step 2: Rename the header "[Tokyo Night]" to "[Tokyo Night Custom]".
; Step 3: Customize color hex values (#RRGGBB).
;=============================================================================
[Ayu]
colour-mode=indexed

background=transparent
background-highlight=#3b5070

chart-border=#bae67e
chart-y-axis=#59a6e0

col-cmd-normal-user-space=#59a6e0
col-cmd-low-priority=#0000FF
col-cmd-high-cpu=#ffa759
Expand Down
17 changes: 16 additions & 1 deletion src/taskmon/Assets/Themes/Catppuccin.theme
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
[Catppuccin]
;=============================================================================
; Task Monitor (taskmon) - Built-in Theme
;=============================================================================
; IMPORTANT:
; Any modifications to default/shipped theme files will be reset automatically
; when taskmon runs or updates.
;
; How to create a custom theme:
; Step 1: Copy this file to a new name (e.g. "Tokyo Night Custom.theme").
; Step 2: Rename the header "[Tokyo Night]" to "[Tokyo Night Custom]".
; Step 3: Customize color hex values (#RRGGBB).
;=============================================================================
[Catppuccin]
colour-mode=indexed

background=transparent
background-highlight=#3b5070

chart-border=#a6e3a1
chart-y-axis=#89b4fa

col-cmd-normal-user-space=#89b4fa
col-cmd-low-priority=#0000FF
col-cmd-high-cpu=#cba6f7
Expand Down
17 changes: 16 additions & 1 deletion src/taskmon/Assets/Themes/Cobalt2.theme
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
[Cobalt2]
;=============================================================================
; Task Monitor (taskmon) - Built-in Theme
;=============================================================================
; IMPORTANT:
; Any modifications to default/shipped theme files will be reset automatically
; when taskmon runs or updates.
;
; How to create a custom theme:
; Step 1: Copy this file to a new name (e.g. "Tokyo Night Custom.theme").
; Step 2: Rename the header "[Tokyo Night]" to "[Tokyo Night Custom]".
; Step 3: Customize color hex values (#RRGGBB).
;=============================================================================
[Cobalt2]
colour-mode=indexed

background=transparent
background-highlight=#0050A4

chart-border=#ffc600
chart-y-axis=#a5ff90

col-cmd-normal-user-space=#a5ff90
col-cmd-low-priority=#ff628c
col-cmd-high-cpu=#ba55d3
Expand Down
17 changes: 16 additions & 1 deletion src/taskmon/Assets/Themes/Cyberpunk 2077.theme
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
[Cyberpunk 2077]
;=============================================================================
; Task Monitor (taskmon) - Built-in Theme
;=============================================================================
; IMPORTANT:
; Any modifications to default/shipped theme files will be reset automatically
; when taskmon runs or updates.
;
; How to create a custom theme:
; Step 1: Copy this file to a new name (e.g. "Tokyo Night Custom.theme").
; Step 2: Rename the header "[Tokyo Night]" to "[Tokyo Night Custom]".
; Step 3: Customize color hex values (#RRGGBB).
;=============================================================================
[Cyberpunk 2077]
colour-mode=indexed

background=transparent
background-highlight=#6272A4

chart-border=#E455AE
chart-y-axis=#FDF500

col-cmd-normal-user-space=#FDF500
col-cmd-low-priority=#37EBF3
col-cmd-high-cpu=#37EBF3
Expand Down
Loading
Loading