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

Improves-snap-ergonomics #1578

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

jaresty
Copy link
Contributor

@jaresty jaresty commented Oct 20, 2024

This implements a few changes:

  1. The window with focus will be the first one spoken with all layouts now
  2. Speaking the layout alone ('snap clock' or similar) will rotate the focused windows in focus the top number in the spoken layout name
  3. Unusable layouts cannot be spoken. There are now two lists: one for layouts that are valid in pairs, one that is a list for layouts that are valid in trios.
  4. Added a grammar for snapping application windows or windows by stack order to specific places in a layout. You can say "snap clock app1 app2 third" to snap into a clock arrangement with windows one and two from apps 1 and 2 and the third window being the third from the top from when you spoke the command.
  5. Added a "gap" layout item which can be used to insert spaces in a layout. Say "snap clock gap app1" to place app1 in the top right.

TODO community meetup feedback

  • Create a fallback in snap_window_to_position in case people were hardcoding the spoken forms - we don't want them to break. We can just check if it's not in the map and see if the HammerCase version is, and show an alert but make the code work for now, can remove after six months
  • Create Talon list for the spoken forms of layouts
  • possibly convert snap identifiers to SHOUT_CASE to match formatters
  • lay → layout
  • better pull request description

Copy link
Collaborator

@nriley nriley left a comment

Choose a reason for hiding this comment

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

From the community backlog session: we had a few specific comments on your implementation but are not sure the complexity of this implementation it's something we want to have in community.

core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_management.talon Outdated Show resolved Hide resolved
@jaresty jaresty requested a review from nriley October 26, 2024 23:29
@phillco
Copy link
Collaborator

phillco commented Oct 29, 2024

I think it's worth the complexity to get this in, personally. Window management with layouts is a good fit for voice, given the powerful nature of the grammar (and vs what could be done by the keyboard), so I think it's worth the complexity. It also improves functionality that's already been added to community. I also foresee building other workflows on this. Lastly, I think the layout logic could be moved to its own file, if needed so the commands can just be ignored if unwanted.

Unless other reviewers feel super strongly, I intend to work on reviewing with a goal of merging this with @jaresty -- if other maintainers disagree, just reach out to me and we can chat; I couldn't attend the session but got the sense that the opposition wasn't too strongly opinionated . I'll double check with maintainers before merging though. Lacking a specific time we can also can discuss this upcoming Saturday.

Copy link
Collaborator

@phillco phillco left a comment

Choose a reason for hiding this comment

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

Let's move this into its own file for isolation purposes. You can refactor the existing actions to support snapping an arbitrary window (which I think would already be a good change) which I think will remove your dependency on this file's private members.

     def snap_window(position: RelativeScreenPos, window: Optional[Window]) -> None:
        """Move the active window to a specific position on its current screen, given a `RelativeScreenPos` object."""
        if window is None:
            window = ui.active_window()
        _snap_window_helper(window, position)

    def snap_window_to_position(position_name: str, window: Optional[Window]) -> None:
        """Move the active window to a specifically named position on its current screen, using a key from `_snap_positions`."""
        actions.user.snap_window(_snap_positions[position_name], window=window)```

core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
@jaresty jaresty requested a review from phillco October 30, 2024 14:43
@jaresty
Copy link
Contributor Author

jaresty commented Oct 30, 2024

I made quite a few changes based on your feedback so it would be really helpful if you could give it another look-thanks!

core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_snap.py Outdated Show resolved Hide resolved
from dataclasses import dataclass
from datetime import datetime

"""Tools for laying out windows in an arrangement """
Copy link
Collaborator

Choose a reason for hiding this comment

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

Probably shouldn't be floating in the middle of the imports

core/windows_and_tabs/window_layout.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_layout.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_layout.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_layout.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_layout.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_layout.py Outdated Show resolved Hide resolved
core/windows_and_tabs/window_layout.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@phillco phillco left a comment

Choose a reason for hiding this comment

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

.

@jaresty
Copy link
Contributor Author

jaresty commented Nov 2, 2024

I made most of the changes that we discussed today. I'm holding off on the 'lay again' helper that we discussed though because there are some things I'm not sure about how to handle in terms of edge cases so I want to focus on this functionality first. Specifically I wasn't sure what to do if you did not have a previous layout since I am currently using none as a way to signal that the layout had been manually adjusted, which might complicate which behavior is correct when someone then tries to 'lay again'-I'm open to suggestions here.

@nriley nriley marked this pull request as draft November 2, 2024 16:43
@jaresty jaresty requested a review from phillco November 2, 2024 21:50
@jaresty
Copy link
Contributor Author

jaresty commented Nov 6, 2024

@nriley I see that you marked this as a draft - I'm not planning to change any more unless I get feedback to do so. Is it ok to mark it ready for review now?

@nriley
Copy link
Collaborator

nriley commented Nov 6, 2024

@nriley I see that you marked this as a draft - I'm not planning to change any more unless I get feedback to do so. Is it ok to mark it ready for review now?

Sure! We just wanted to separate it out during our review session as it was still being worked on.

@jaresty
Copy link
Contributor Author

jaresty commented Nov 6, 2024

Thanks! I heard from @phillco that I do still have some feedback coming so I'll wait until we meet to discuss.

AndreasArvidsson pushed a commit that referenced this pull request Jan 11, 2025
…Snap Name List (#1629)

## Background:
We want to be able to call these snap positions from another module
(#1578), but the existing action takes a spoken form. We'd rather not
build a dependency on those, because they can be brittle if the user
changes them; it's become a best practice recently (formatters, etc) to
use static identifiers instead, and use a Talon list to provide the
spoken form.

## Change:

- This change changes the keys of the snap positions dictionary to have
static identifiers, instead of the previous spoken forms.
- A talon list is introduced to map the spoken forms to the new
identifiers.
- To reduce user friction, as people are probably calling the existing
action with a spoken form, we'll attempt to convert it to the new
identifier if we can, to allow the action to succeed, although we will
still show a deprecation warning so they can update their code.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
@jaresty jaresty force-pushed the improves-snap-ergonomics branch from ffed9df to efb49b6 Compare January 11, 2025 22:49
@jaresty jaresty marked this pull request as ready for review January 11, 2025 23:23
Make it so you can only speak a valid layout

There are two kinds of valid layouts:
- layouts that are pairs
- layout that are trios

While there maybe layout arrangements that are greater than twos and threes, it's difficult to say the number of applications required to trigger those layouts.

Refactor layouts to operate on windows in preparation for window layouts.

Enable using the trio and pair snap layouts to rotate layouts

- now if you say 'snap clock' twice in a row it will rotate the focused window

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Start counting for layouts at the active window

Extract _top_n_windows helper function in preparation for adding ordinals for focus

Provide convenience function to pick a specific window to focus

- If you say 'snap first split' it will split without changing the order
- If you say 'snap third clock' will swap the third window with the first, so you can repeat to swap them back

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Make the error message a little more intuitive

Provide away to snap a window by index

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Provide a shortcut to focus an application and snap to a layout at the same time

Slightly adjust grammar based on feedback

Optimized for reducing dfa rules

- This requires a little bit more manual finesse than the previous version but it does allow you to snap specific applications and leave others alone. If you say, 'snap clock code', for example, it won't affect anything but the code windows. You can say, 'snap clock code all' to effect windows after code by appending all other windows after the code windows. If you say, 'snap clock' alone it will continue to rotate the windows as before.

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Handle error resizing window

- There might be a better approach, but this will at least try to snap all windows specified.  (ran into an unresizable window in zoom)

Gracefully handle snap errors

- If a snap error happens, it will continue trying to snap
- Struggled to maintain rotate behavior, but it seems to be working presently

Implement gap support

Refactor some duplicate code

Cleanup extra print statements

Prevent an error if you tried to pop a zero number of snapped windows

Respond opal request feedback by making the snapping move to the right instead of the left

Now it only rotates when focus was done by snap layout first

- Next need to reset this variable when focus is done by other means

Make it so snap layout only rotates when it was the last thing used to snap

Optimized to fix race condition

- Calling focus has a delay so, we have to wait until the function is done before we can be sure that we can start listening for events again

Responding to pull request feedback

- I don't want to make a required argument because using the layout with no arguments is useful. What do you think about changing this name to lay?

Make window layout into a data class responding to pull request feedback

Responding to pull request feedback

- Removed debug print statement
- Renamed to reflect that all windows is not really the correct name: it's really all candidate windows will be considered for layout

Exposed public method for snapping windows to position by name

Clarify that the snap failure is normal and provide additional details

Remove usage of time delays to ensure snapping does not have a race

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Breakout layout to another file

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Refactor window layout code to clarify

Handle window focusing errors

First pass at pull request feedback from today

[pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

Removed some debug printing and an exception that I can't make more specific yet

Update core/windows_and_tabs/window_snap.py

Co-authored-by: Phil Cohen <phillip@phillip.io>

Fixed typo

Removed debug logs

Need to pass window from calling function

The active window is not always in the list passed in

Index filtering should be based on the index in all windows not based on the index in windows passed in

Cleanup imports

Rescue another exception type that I ran into

Respond to pull request feedback:

- There was a concern that some people might want to rename these position names
- This allows for renaming them in one location without breaking the other functionality

Extract window snap positions as a talon list

Make GapWindow into a proper class

Handle the deep copy earlier

Ensure that snap layout finishes by resetting the layout in progress

Add types to pick_split_arrangement and cleanup snap_layout a bit

Skip filtering of application windows

- sometimes filters windows that should not be filter

Remove filter nonviable windows

- It doesn't work as effectively as just skipping when the snap fails

Removed debug logging

Revert "Remove filter nonviable windows"

This reverts commit 463d68a.

Remove stray debug print statement

- Fix repeater
- Fix rotating multiple times - store an offset counter and increase it each time
- various other code tweaks for clarity

Use idiomatic types for optionals

cleanup

window_layout: documentation

window_layout: fix gaps, repeating with an independent command

Reset the rotation count when the layout windows change

Respond to pull request feedback

- It is cleaner to add to the existing condition rather than resetting the rotation count as a one-off condition

Respond full request feedback

- According to aegis, copy_windows was not doing anything. I'm not sure I understand this feedback so feel free to revert if you disagree.

Respond to pull request feedback

- Rather than specifying the layout name and number and having it picked by the number of windows specified, it is more intuitive to use a different name for each layout.

 Respond to pull request feedback

 - We were asked to make it so that the split position names could be renamed easily
@jaresty jaresty force-pushed the improves-snap-ergonomics branch from 8ae3b4b to a8f5af0 Compare January 16, 2025 00:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants