Skip to content

Commit

Permalink
feat(wm): add saving/loading of layouts to file
Browse files Browse the repository at this point in the history
This commit expands on the autosave/load functionality to allow saving
and loading layouts from any file.

Handling relative paths and paths with ~ on Windows is a little tricky
so I added a helper fn to komorebic to deal with this, ensuring all the
processing happens in komorebic before the messages get sent to komorebi
for processing.

There will still some lingering uses of ContextCompat around the
codebase which I also took the opportunity to clean up and replace with
ok_or_else + anyhow!().

windows-rs is also updated to 0.20.1 in the lockfile.

resolve #41
  • Loading branch information
LGUG2Z committed Sep 22, 2021
1 parent 80bcb51 commit b9a4092
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 41 deletions.
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 25 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,26 @@ passing it as an argument to the `--implementation` flag:
komorebic.exe toggle-focus-follows-mouse --implementation komorebi
```

#### Saving and Loading Resized Layouts

If you create a BSP layout through various resize adjustments that you want to be able to restore easily in the future,
it is possible to "quicksave" that layout to the system's temporary folder and load it later in the same session, or
alternatively, you may save it to a specific file to be loaded again at any point in the future.

```powershell
komorebic.exe quick-save # saves the focused workspace to $Env:TEMP\komorebi.quicksave.json
komorebic.exe quick-load # loads $Env:TEMP\komorebi.quicksave.json on the focused workspace
komorebic.exe save ~/layouts/primary.json # saves the focused workspace to $Env:USERPROFILE\layouts\primary.json
komorebic.exe load ~/layouts/secondary.json # loads $Env:USERPROFILE\layouts\secondary.json on the focused workspace
```

These layouts can be applied to arbitrary collections of windows on any workspace, as they only track the layout
dimensions and are not coupled to the applications that were running at the time of saving.

When layouts that expect more or less windows than the number currently on the focused workspace are loaded, `komorebi`
will automatically reconcile the difference.

## Configuration with `komorebic`

As previously mentioned, this project does not handle anything related to keybindings and shortcuts directly. I
Expand All @@ -198,10 +218,12 @@ each command.
start Start komorebi.exe as a background process
stop Stop the komorebi.exe process and restore all hidden windows
state Show a JSON representation of the current window manager state
quick-save Quicksave the current resize layout dimensions
quick-load Load the last quicksaved resize layout dimensions
query Query the current window manager state
log Tail komorebi.exe's process logs (cancel with Ctrl-C)
quick-save Quicksave the current resize layout dimensions
quick-load Load the last quicksaved resize layout dimensions
save Save the current resize layout dimensions to a file
load Load the resize layout dimensions from a file
focus Change focus to the window in the specified direction
move Move the focused window in the specified direction
stack Stack the focused window in the specified direction
Expand Down Expand Up @@ -275,6 +297,7 @@ used [is available here](komorebi.sample.with.lib.ahk).
- [x] Resize window container in direction
- [ ] Resize child window containers by split ratio
- [x] Quicksave and quickload layouts with resize dimensions
- [x] Save and load layouts with resize dimensions to/from specific files
- [x] Mouse drag to swap window container position
- [x] Mouse drag to resize window container
- [x] Configurable workspace and container gaps
Expand Down
3 changes: 3 additions & 0 deletions komorebi-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![warn(clippy::all, clippy::nursery, clippy::pedantic)]
#![allow(clippy::missing_errors_doc)]

use std::path::PathBuf;
use std::str::FromStr;

use clap::ArgEnum;
Expand Down Expand Up @@ -54,6 +55,8 @@ pub enum SocketMessage {
Retile,
QuickSave,
QuickLoad,
Save(PathBuf),
Load(PathBuf),
FocusMonitorNumber(usize),
FocusWorkspaceNumber(usize),
ContainerPadding(usize, usize, i32),
Expand Down
23 changes: 23 additions & 0 deletions komorebi/src/process_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,29 @@ impl WindowManager {

let resize: Vec<Option<Rect>> = serde_json::from_reader(file)?;

workspace.set_resize_dimensions(resize);
self.update_focused_workspace(false)?;
}
SocketMessage::Save(path) => {
let workspace = self.focused_workspace_mut()?;
let resize = workspace.resize_dimensions();

let file = OpenOptions::new()
.write(true)
.truncate(true)
.create(true)
.open(path)?;

serde_json::to_writer_pretty(&file, &resize)?;
}
SocketMessage::Load(path) => {
let workspace = self.focused_workspace_mut()?;

let file = File::open(&path)
.map_err(|_| anyhow!("no file found at {}", path.display().to_string()))?;

let resize: Vec<Option<Rect>> = serde_json::from_reader(file)?;

workspace.set_resize_dimensions(resize);
self.update_focused_workspace(false)?;
}
Expand Down
7 changes: 3 additions & 4 deletions komorebi/src/window_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use std::sync::Arc;
use std::thread;

use color_eyre::eyre::anyhow;
use color_eyre::eyre::ContextCompat;
use color_eyre::Result;
use crossbeam_channel::Receiver;
use hotwatch::notify::DebouncedEvent;
Expand Down Expand Up @@ -591,9 +590,9 @@ impl WindowManager {
) {
let unaltered = workspace.layout().calculate(
&work_area,
NonZeroUsize::new(len).context(
"there must be at least one container to calculate a workspace layout",
)?,
NonZeroUsize::new(len).ok_or_else(|| {
anyhow!("there must be at least one container to calculate a workspace layout")
})?,
workspace.container_padding(),
workspace.layout_flip(),
&[],
Expand Down
9 changes: 5 additions & 4 deletions komorebi/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::collections::VecDeque;
use std::num::NonZeroUsize;

use color_eyre::eyre::anyhow;
use color_eyre::eyre::ContextCompat;
use color_eyre::Result;
use getset::CopyGetters;
use getset::Getters;
Expand Down Expand Up @@ -154,9 +153,11 @@ impl Workspace {
} else if !self.containers().is_empty() {
let layouts = self.layout().calculate(
&adjusted_work_area,
NonZeroUsize::new(self.containers().len()).context(
"there must be at least one container to calculate a workspace layout",
)?,
NonZeroUsize::new(self.containers().len()).ok_or_else(|| {
anyhow!(
"there must be at least one container to calculate a workspace layout"
)
})?,
self.container_padding(),
self.layout_flip(),
self.resize_dimensions(),
Expand Down
16 changes: 12 additions & 4 deletions komorebic.lib.sample.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@ State() {
Run, komorebic.exe state, , Hide
}

Query(state_query) {
Run, komorebic.exe query %state_query%, , Hide
}

Log() {
Run, komorebic.exe log, , Hide
}

QuickSave() {
Run, komorebic.exe quick-save, , Hide
}
Expand All @@ -20,12 +28,12 @@ QuickLoad() {
Run, komorebic.exe quick-load, , Hide
}

Query(state_query) {
Run, komorebic.exe query %state_query%, , Hide
Save(path) {
Run, komorebic.exe save %path%, , Hide
}

Log() {
Run, komorebic.exe log, , Hide
Load(path) {
Run, komorebic.exe load %path%, , Hide
}

Focus(operation_direction) {
Expand Down
Loading

0 comments on commit b9a4092

Please sign in to comment.