Skip to content

Commit

Permalink
feat(ux)!: ✨ implement new command flow (#28) (#90)
Browse files Browse the repository at this point in the history
* feat(ux): 🚧 begin work on new command flow (#28)

* feat(ux): 🚧 add `start` result (#28)

* refactor: 🚧 use existing method to create `start` results (#28)

* feat(ux): 🚧 add `continue` results (#28)

* feat(state): 🚧 reset state when query is empty (#28)

* feat(ux): ✨ implement `@` to select project (#28)

* feat(ux): 🚸 remove leading `\` if query is no longer empty (#28)

* feat(ux): 🚧 set scores for `start` results (#28)

* feat(ux): 🚧 implement transition from `continue` to `start` (#28)

* refactor: 🚧 refactor results source state variable (#28)

* perf: ⚡ get results in parallel (#28)

* feat(ux): 🚧 add other commands to results (#28)

* feat(ux): ✨ implement command selection (#28)

`tgl` will fill:
	1. Start empty time entry
	2. List of commands

`tgl ...` will fill:
	1. Start ...
	2. Fuzzy filtered past ... entries
	3. Fuzzy filtered ... commands

`tgl [command-name]` will:
	1. Auto-trigger the command.

You can `tgl \[command-name]` to escape the command auto-trigger and create it as a time entry.

* fix(ux): 🐛 gracefully handle project selection exit (#28)

ie non-expected exit, such as `tgl @` -> `tgl \@`

* feat(ux): 🚸 implement `Alt` key modifier to instantly continue (#28)

* feat(ux): 🚸 restore `start` usage tips (#28)

* refactor: ⚰️ remove old `QueryAsync()` logic (#28)

* feat(ux): ✨ perform `@` project selection in-place (#28)

ie, do not delete the preceeding query

* fix(ux): 🐛 escape potential commands when using `continue` (#28)

* feat(ux): 🚸 add usage tip for `@` project selection (#28)

* feat(ux)!: 🚸 use `@` project selection for `edit` (#28)

* docs(readme): 💡 fix todo comment (#28)

* perf: ⚡ only refresh cache on empty query (#28)

* feat(ux): 🚸 implement `Alt` quick-start from project selection (#28)

* fix(ux): 🐛 fix transition from `reports` to `start` (#28)

* feat(ux): 🚸 improve command escaping (#28)

* feat(ux): 🚸 support `-t` offset from `Alt` project selection quick-start (#28)

* refactor: 💡 remove `wontfix` todo (#28)

* fix(ux): 🐛 fix exclusive result source for `start` project selection (#28)

* feat(ux): 🚸 remove `continue` result if identical to query (#28)

* fix(ux): 🐛 do not change `edit` project if unselected (#28)

* docs(readme): 📝 document new command flow (#28)

* docs(readme): 📝 add missing linebreak

BREAKING CHANGE: See release notes/below.
1. `tgl start` and `tgl continue` command keywords have been removed.
2. `start` and `continue` are now top-level commands.
4. You can no longer quick-start commands with eg `tgl o`, you must now type the command in full (or select it from the top-level results)
5. `start` project selection is no longer enforced at the beginning; it is optionally triggered at any point with the `@` symbol.
6. `edit` project selection uses `@` instead of `-p` accordingly.
  • Loading branch information
JamesNZL authored Jul 4, 2023
1 parent c89e033 commit 92d2cea
Show file tree
Hide file tree
Showing 39 changed files with 820 additions and 457 deletions.
207 changes: 140 additions & 67 deletions README.md

Large diffs are not rendered by default.

Binary file removed assets/screenshots/continue.jpg
Binary file not shown.
Binary file added assets/screenshots/continue/selected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/continue/selecting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed assets/screenshots/default.jpg
Binary file not shown.
File renamed without changes
Binary file removed assets/screenshots/edit.jpg
Binary file not shown.
Binary file added assets/screenshots/edit/fuzzy-query.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/edit/selected-project.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/edit/selecting-project.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/edit/selecting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
Binary file removed assets/screenshots/start-options.jpg
Binary file not shown.
Binary file removed assets/screenshots/start-past.jpg
Binary file not shown.
Binary file removed assets/screenshots/start.jpg
Binary file not shown.
Binary file added assets/screenshots/start/new-past.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/start/new-selected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/screenshots/start/new-selecting.png
Binary file added assets/screenshots/start/new.png
Binary file added assets/screenshots/start/projects.png
File renamed without changes
Binary file added assets/screenshots/tgl/command-name.png
Binary file added assets/screenshots/tgl/empty-query.png
Binary file added assets/screenshots/tgl/escaped-command-name.png
Binary file added assets/screenshots/tgl/fuzzy-query.png
51 changes: 10 additions & 41 deletions src/Main.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Windows.Controls;
using System.Collections.Generic;
using System.Linq;
// using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flow.Launcher.Plugin.TogglTrack.ViewModels;
Expand All @@ -19,14 +19,14 @@ public class Main : IAsyncPlugin, ISettingProvider

internal TogglTrack? _togglTrack;

private (
string LastCommand,
// ! this is needed as tuples must have minimum 2 elements
bool? _null
) _state = (
LastCommand: string.Empty,
null
);
// private (
// string LastCommand,
// // ! this is needed as tuples must have minimum 2 elements
// bool? _null
// ) _state = (
// LastCommand: string.Empty,
// null
// );

/// <summary>
/// Runs on plugin initialisation.
Expand Down Expand Up @@ -77,38 +77,7 @@ public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
return this._togglTrack.NotifyInvalidToken();
}

if (string.IsNullOrWhiteSpace(query.Search))
{
return await this._togglTrack.GetDefaultHotKeys(token, prefetch: true);
}

string command = query.FirstSearch;
if (!Settings.Commands.Contains(command) && command == this._state.LastCommand)
{
command = (await this._togglTrack.GetDefaultHotKeys(token))
.GroupBy(result => this._context!.API.FuzzySearch(query.FirstSearch, result.Title).Score)
.MaxBy(group => group.Key)
?.MaxBy(result => result.Score)
?.Title
?? query.FirstSearch;
this._context!.API.ChangeQuery($"{query.ActionKeyword} {command} ");
}
this._state.LastCommand = command;

return (command.ToLower()) switch
{
Settings.StartCommand => await this._togglTrack.RequestStartEntry(token, query),
Settings.StopCommand => await this._togglTrack.RequestStopEntry(token, query),
Settings.ContinueCommand => await this._togglTrack.RequestContinueEntry(token, query),
Settings.EditCommand => await this._togglTrack.RequestEditEntry(token, query),
Settings.DeleteCommand => await this._togglTrack.RequestDeleteEntry(token, query),
Settings.ReportsCommand => await this._togglTrack.RequestViewReports(token, query),
_ => (await this._togglTrack.GetDefaultHotKeys(token))
.FindAll(result =>
{
return this._context!.API.FuzzySearch(query.Search, result.Title).Score > 0;
}),
};
return await this._togglTrack.RequestResults(token, query);
}

/// <summary>
Expand Down
20 changes: 12 additions & 8 deletions src/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,26 @@ namespace Flow.Launcher.Plugin.TogglTrack
/// </Summary>
public class Settings
{
internal const string StartCommand = "start";
internal const string StopCommand = "stop";
internal const string ContinueCommand = "continue";
internal const string EditCommand = "edit";
internal const string DeleteCommand = "delete";
internal const string ReportsCommand = "reports";
internal const string BrowserCommand = "browser";
internal const string RefreshCommand = "refresh";
internal const string HelpCommand = "help";
internal const string RefreshCommand = "refresh";
internal static readonly string[] Commands = new string[] {
StartCommand,
StopCommand,
ContinueCommand,
EditCommand,
DeleteCommand,
ReportsCommand,
BrowserCommand,
RefreshCommand,
HelpCommand,
RefreshCommand,
};

internal const string EditProjectFlag = "-p";
internal const string ProjectPrefix = "@";
internal const string EscapeCharacter = @"\";

internal const string ClearDescriptionFlag = "-C";
internal const string TimeSpanFlag = "-t";
internal const string TimeSpanEndFlag = "-T";
Expand All @@ -39,19 +37,25 @@ public class Settings
internal const string NoProjectName = "No Project";
internal const string NoClientName = "No Client";
internal const string EmptyDescription = "(no description)";
internal const string EmptyTimeEntry = "an empty time entry";

internal const string UsageTipTitle = "Usage Tip";
internal const string UsageExampleTitle = "Usage Example";
internal const string UsageWarningTitle = "Usage Warning";

internal static readonly Regex QueryEscapingRegex = new Regex(@$"(\{Settings.EscapeCharacter}(?!\{Settings.EscapeCharacter}))");
internal static readonly Regex UnescapedProjectRegex = new Regex(@$"(?<!\{Settings.EscapeCharacter}){Settings.ProjectPrefix}");
internal static readonly Regex UnescapedFlagRegex = new Regex(@" -");
internal static readonly Regex ProjectCaptureRegex = new Regex(@$"(?<!\{Settings.EscapeCharacter}){Settings.ProjectPrefix}(.*)");
internal static readonly Regex ReportsSpanOffsetRegex = new Regex(@"-(\d+)");

internal enum ReportsSpanKey
{
Day,
Week,
Month,
Year,
}
internal static readonly Regex ReportsSpanOffsetRegex = new Regex(@"-(\d+)");
internal static readonly List<ReportsSpanCommandArgument> ReportsSpanArguments = new List<ReportsSpanCommandArgument>
{
new ReportsSpanCommandArgument
Expand Down
67 changes: 51 additions & 16 deletions src/Structures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -201,16 +201,25 @@ public int GetScoreByDuration(TimeEntry? longest)
return (int)(this.Duration >> 2);
}

public string? GetRawDescription(bool withTrailingSpace = false, bool escapePotentialFlags = false)
public string? GetRawDescription(bool withTrailingSpace = false, bool escapeCommands = false, bool escapePotentialSymbols = false)
{
if (string.IsNullOrEmpty(this._rawDescription))
{
return string.Empty;
}

string rawDescription = (escapePotentialFlags)
? TransformedQuery.EscapeDescription(this._rawDescription)
: this._rawDescription;
string rawDescription = this._rawDescription;

if (escapePotentialSymbols)
{
rawDescription = TransformedQuery.EscapeSymbols(rawDescription);
}

// ! This must be applied after escaping flags (or we will get double escaping)
if (escapeCommands)
{
rawDescription = TransformedQuery.EscapeCommand(rawDescription);
}

if (!withTrailingSpace)
{
Expand All @@ -220,16 +229,25 @@ public int GetScoreByDuration(TimeEntry? longest)
return $"{rawDescription} ";
}

public string GetDescription(bool escapePotentialFlags = false)
public string GetDescription(bool escapeCommands = false, bool escapePotentialSymbols = false)
{
if (string.IsNullOrEmpty(this._rawDescription))
{
return Settings.EmptyDescription;
}

return (escapePotentialFlags)
? TransformedQuery.EscapeDescription(this._rawDescription)
: this._rawDescription;
string description = this._rawDescription;
if (escapePotentialSymbols)
{
description = TransformedQuery.EscapeSymbols(description);
}
// ! This must be applied after escaping flags (or we will get double escaping)
if (escapeCommands)
{
description = TransformedQuery.EscapeCommand(description);
}

return description;
}

public DateTimeOffset StartDate
Expand Down Expand Up @@ -567,16 +585,24 @@ public int GetScoreByDuration()
return (int)(this.Seconds >> 2);
}

public string? GetRawTitle(bool withTrailingSpace = false, bool escapePotentialFlags = false)
public string? GetRawTitle(bool withTrailingSpace = false, bool escapeCommands = false, bool escapePotentialSymbols = false)
{
if (string.IsNullOrEmpty(this._rawTitle))
{
return string.Empty;
}

string rawTitle = (escapePotentialFlags)
? TransformedQuery.EscapeDescription(this._rawTitle)
: this._rawTitle;
string rawTitle = this._rawTitle;

if (escapePotentialSymbols)
{
rawTitle = TransformedQuery.EscapeSymbols(rawTitle);
}
// ! This must be applied after escaping flags (or we will get double escaping)
if (escapeCommands)
{
rawTitle = TransformedQuery.EscapeCommand(rawTitle);
}

if (!withTrailingSpace)
{
Expand All @@ -586,16 +612,25 @@ public int GetScoreByDuration()
return $"{rawTitle} ";
}

public string GetTitle(bool escapePotentialFlags = false)
public string GetTitle(bool escapeCommands = false, bool escapePotentialSymbols = false)
{
if (string.IsNullOrEmpty(this._rawTitle))
{
return Settings.EmptyDescription;
}

return (escapePotentialFlags)
? TransformedQuery.EscapeDescription(this._rawTitle)
: this._rawTitle;
string title = this._rawTitle;
if (escapePotentialSymbols)
{
title = TransformedQuery.EscapeSymbols(title);
}
// ! This must be applied after escaping flags (or we will get double escaping)
if (escapeCommands)
{
title = TransformedQuery.EscapeCommand(title);
}

return title;
}

public TimeSpan Elapsed
Expand Down
Loading

0 comments on commit 92d2cea

Please sign in to comment.