-
-
Notifications
You must be signed in to change notification settings - Fork 239
Implement focus dfs-next/dfs-prev. #1243
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
base: main
Are you sure you want to change the base?
Conversation
820d9df
to
9d68666
Compare
I added an implementation of swap as well (which depends on part of the implementation of |
Somewhat unfortunate/amusing timing, I had been poking at this same feature (and learning Swift), though I don't consider mine ready for a PR yet: main...timobenn:AeroSpace:focus-dfs-next-prev-248 A couple of things to note:
|
@timobenn wdym? This PR supports focusing floating windows via |
@nikitabobko when I'd tested mine last week, I came to the conclusion that (edit: not on a Mac right now, otherwise I'd pull & test) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't read all of the code yet, here the first portion of comments
Overall - looks good, thanks
I don't care if the commits are in one big PR or two separate PRs. I review commit by commit anyway.
If your second commit depends on the first one, I understand why you put them into a single PR. Otherwise, you might yourself prefer to split it into two different PRs, because the code review will take longer with several commits in one PR
@@ -0,0 +1,45 @@ | |||
= aerospace-swap(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update ./docs/commands.adoc
In future, it will be probably auto-generated #1027
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
docs/aerospace-swap.adoc
Outdated
== Synopsis | ||
[verse] | ||
// tag::synopsis[] | ||
aerospace swap [-h|--help] [--move-focus-to-target] [--wrap-around] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--move-focus-to-target
is wrong. Probably you meant --swap-focus
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, fixed
allowInConfig: true, | ||
help: swap_help_generated, | ||
options: [ | ||
"--swap-focus": trueBoolFlag(\.swapFocus), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the --swap-focus
flag
let args: SwapCmdArgs | ||
|
||
func run(_ env: CmdEnv, _ io: CmdIo) -> Bool { | ||
guard let target = args.resolveTargetOrReportError(env, io), let currentWindow = target.windowOrNil else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please split these two let
s into separate guard
s. Otherwise, if resolveTargetOrReportError
returns nil
, the noWindowIsFocused
error is incorrect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done (though now that I see that target could be overridden by resolveTargetOrReportError
, is it even correct to emit "noWindowIsFocused" in the second guard?
return io.err(noWindowIsFocused) | ||
} | ||
|
||
var targetWindow: Window? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
var targetWindow: Window? | |
let targetWindow: Window? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
case "right": .success(.direction(.right)) | ||
case "dfs-next": .success(.dfsRelative(.next)) | ||
case "dfs-prev": .success(.dfsRelative(.prev)) | ||
default: .failure("Can't parse '\(arg)\'. Possible values: left|down|up|right|dfs-next|dfs-prev") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the hardcoded left|down|up|right|dfs-next|dfs-prev
. I'd prefer to make use of CaseIterable
of every nested case
and combine the result. Or maybe it's even possible to write a generic functions which trverses CaseIterable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same for parsing the argument itself. I don't like the hardcoded case "left"
, case "down"
, case "dfs-next"
. I think it's possible to make use of CaseIterable
at least manually (ideally - automatically, recursively)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed FocusTargetArg to CardinalOrDfsDirection and implemented the CaseIterable and RawRepresentable protocols for it so that parseEnum and unionLiteral can be used.
docs/aerospace-focus.adoc
Outdated
*1. (left|down|up|right) arguments* | ||
|
||
{manpurpose} | ||
|
||
*2. (dfs-next|dfs-prev) arguments* | ||
|
||
Set focus to the window before or after the current window in the depth-first order (top-to-bottom and left-to-right) of windows in the current workspace tree. | ||
In this mode, `--boundaries` must be `workspace` (the default) and `--boundaries-action` can be set to one of `(stop|fail|wrap-around-the-workspace)`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that docs for some of other commands written in this style, but please prefer the style with ARGUMENTS
section like in aerospace-focus-monitor
Other commands that use this style of documentation (e.g. workspace
) will be migrated to ARGUMENTS
-section-style in the future
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the example, switched to ARGUMENTS
-section-style.
@@ -12,6 +12,9 @@ include::util/man-attributes.adoc[] | |||
aerospace focus [-h|--help] [--ignore-floating] | |||
[--boundaries <boundary>] [--boundaries-action <action>] | |||
(left|down|up|right) | |||
aerospace focus [-h|--help] [--ignore-floating] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
--ignore-floating
is also supported here
grammar/commands-bnf-grammar.txt
Outdated
<focus_dir_flag> ::= --boundaries <boundary>|--boundaries-action <dir_boundaries_action>|--ignore-floating; | ||
<focus_dfs_relative_flag> ::= --boundaries-action <dfs_relative_boundaries_action>|--ignore-floating; | ||
<dir_boundaries_action> ::= stop|fail|wrap-around-the-workspace|wrap-around-all-monitors; | ||
<dfs_relative_boundaries_action> ::= stop|fail|wrap-around-the-workspace; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer the shell completion to suggest yet unsupported wrap-around-all-monitors
rather than complicating the grammar
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done - I had left it out because I wasn't sure that wrap-around-all-monitors
made sense for dfs-next/dfs-prev. Within a workspace, the ordering of DFS indices are well defined, but it wasn't clear to me that there was a clear correct next monitor to wrap around to.
grammar/commands-bnf-grammar.txt
Outdated
@@ -20,9 +20,10 @@ aerospace -h; | |||
|
|||
| flatten-workspace-tree [--workspace <workspace>] | |||
|
|||
| focus [<focus_flag>]... (left|down|up|right) [<focus_flag>]... | |||
| focus [<focus_dir_flag>]... (left|down|up|right) [<focus_dir_flag>]... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO "dir" = "direction" is not obvious shortening
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to focus_direction_flag
@timobenn since AeroSpace/Sources/AppBundle/command/impl/FocusCommand.swift Lines 9 to 15 in fb3a863
|
@nikitabobko I must have been running into a weird issue with window state when first launching the debug build on top of a running instance; when I test today I'm able to get both my branch and this PR to acknowledge floating windows correctly, as long as I make sure to fully reset the layout after launch first, before floating any windows. |
If you all have interest in having |
203c892
to
b9b9b86
Compare
Thanks for the review! @timobenn Oops, sorry for the unintended duplication of work - I took your nicer naming for the focus argument, but didn't pull in the monitor wrapping code - feel free to follow up with that if folks are able to agree on what that behavior would be! fwiw, I didn't attempt to implement |
b9b9b86
to
3a0b207
Compare
No worries! Risk I took by working so slowly without broadcasting I was doing it. For wrapping around all monitors I was using this logic:
For the limited amount of manual testing I'd done so far, that logic was feeling natural. |
Ah, I see - I wasn't aware that monitors already had some fixed ordering to them. Re the earlier discussion about floating windows - it looks like the current trick for dealing with floating windows inserts them into the window tree at a location depending on its location on the screen. As a result, they are assigned an unintuitive DFS position when using dfs-next and dfs-prev - I think I would actually prefer we explicitly sorted floating windows after all of the windows in the tree instead - can update the implementation to do that if there are no objections (though I guess the downside is that the command might cycle through multiple floating windows in an arbitrary-feeling order instead - there may also be implications for the behavior of things like --dfs-index if we are deciding to define a meaningful DFS index value for floating windows). |
I do agree that floating windows being mixed among the leaves the way they currently are feels a bit weird in the context of dfs-next/prev. I'm not sure how much better grouping them together would feel (though I expect it would be at least a little), or how much complexity would be added by handling floating windows differently based on the focus target. |
3a0b207
to
f4a4a73
Compare
This allows switching to the next/prev window from the current one in the depth-first order of the windows in the current workspace tree. This is convenient, as it allows users to shift focus through a workspace's windows in a more predictable way than the directional movement commands, where the move target can depend on invisible most-recently-used state. _fixes nikitabobko#248
`aerospace swap` swaps the currently focused window with a window in a cardinal direction or with the next/prev window in the depth first order of windows in the workspace. Target window selection works identically to the focus command (so the cardinal directions respect MRU). _fixes nikitabobko#8
f4a4a73
to
a1b88a5
Compare
This allows switching to the next/prev window from the current one in
the depth-first order of the windows in the current workspace tree.
This is convenient, as it allows users to shift focus through a
workspace's windows in a more predictable way than the directional
movement commands, where the move target can depend on invisible
most-recently-used state.
_fixes #248