ianyh / Amethyst

Automatic tiling window manager for macOS à la xmonad.
https://ianyh.com/amethyst/
MIT License
14.58k stars 486 forks source link

[Feature Request] Adding Export/Import Functionality #1217

Open seinmon opened 2 years ago

seinmon commented 2 years ago

Is your feature request related to a problem? Please describe. I try to keep everything consistent between my machines (macOS, macOS, Linux). Since the default keybindings of Amethyst don't match my i3 keybindings, I have to make changes in both layouts and shortcuts. Manually configuring everything on different machines is time-consuming and annoying.

(Somewhat similar to #301 and #331)

Describe the solution you'd like An option to export and import configurations, similar to exporting and importing of profiles in terminal.app.

Exporting/importing avoids conflicts between dotfiles and the GUI Preferences, and exported configurations could be simply a copy of ~/Library/Preferences/com.amethyst.Amethyst.plist, or a JSON file that excludes unnecessary data.

vizcay commented 2 years ago

Describe the solution you'd like An option to export and import configurations, similar to exporting and importing of profiles in terminal.app.

Exporting/importing avoids conflicts between dotfiles and the GUI Preferences, and exported configurations could be simply a copy of ~/Library/Preferences/com.amethyst.Amethyst.plist, or a JSON file that excludes unnecessary data.

IMHO this is suboptiomal: amethyst is targeted towards powerusers. Powerusers don't export / import settings, mostly they store "dot files" in git repositories to share across workstations and backup. Ideally we should be able to link those files into the "standard location" and it should work (e.g. ~/.amethystrc or ~./config/Amethys/config) etc.

vizcay commented 2 years ago

Also, allowing amethys to process command line arguments will solve this issue for most of us I believe: https://github.com/ianyh/Amethyst/issues/301#issuecomment-1088126261.

seinmon commented 2 years ago

I agree that having a configuration file is the best approach, but I don't like the command-line argument approach.

When you create a config file (e.g. in i3wm), the software itself checks for the correctness of the configurations. I haven't used skhd, but I'm sure it can't tell whether or not the commands are written correctly.

Also, Amethyst already has the functionalities related to hotkey management and configuration files. Creating command-line arguments would be overkill.

Creating an import/export feature is not that complicated, and doesn't go against the design decisions that have been made so far. All you have to do is to save the exported shortcuts file somewhere (e.g. your GitHub repo), and config the rest of the stuff with a simple script like https://github.com/ianyh/Amethyst/issues/301#issuecomment-604133418

ianyh commented 2 years ago

Describe the solution you'd like

An option to export and import configurations, similar to exporting and importing of profiles in terminal.app.

Exporting/importing avoids conflicts between dotfiles and the GUI Preferences, and exported configurations could be simply a copy of ~/Library/Preferences/com.amethyst.Amethyst.plist, or a JSON file that excludes unnecessary data.

IMHO this is suboptiomal: amethyst is targeted towards powerusers. Powerusers don't export / import settings, mostly they store "dot files" in git repositories to share across workstations and backup. Ideally we should be able to link those files into the "standard location" and it should work (e.g. ~/.amethystrc or ~./config/Amethys/config) etc.

As a note, I wouldn't say Amethyst is targeted towards power users. I see two parts to it: tiling windows and keyboard control. The latter is pretty power user-ish, but I think lots of people can benefit from the former. I'll note that you can get a lot of the tiling done via mouse these days, and I know someone who isn't really technical that uses it that way and likes it. That's more of a philosophical point than a practical one, but I think it is relevant here.

With regards to dot files, I think a dot file and the ability to import/export are compatible. A dot file in the home directory is a very power user approach, and importing and exporting it through the UI is a more user friendly approach. It seems reasonable to have both.

seinmon commented 2 years ago

@ianyh Thank you for your comment.

I've looked into the code to get a general understanding of how I can add the import/export feature, and I found this function in UserConfiguration:

    private func loadConfigurationFile() {
        let amethystConfigPath = NSHomeDirectory() + "/.amethyst"
        let defaultAmethystConfigPath = Bundle.main.path(forResource: "default", ofType: "amethyst")

        if FileManager.default.fileExists(atPath: amethystConfigPath, isDirectory: nil) {
            configuration = jsonForConfig(at: amethystConfigPath)

            if configuration == nil {
                log.error("error loading configuration")

                let alert = NSAlert()
                alert.alertStyle = .critical
                alert.messageText = "Error loading configuration"
                alert.runModal()
            }
        }

        defaultConfiguration = jsonForConfig(at: defaultAmethystConfigPath ?? "")
        if defaultConfiguration == nil {
            log.error("error loading default configuration")

            let alert = NSAlert()
            alert.alertStyle = .critical
            alert.messageText = "Error loading default configuration"
            alert.runModal()
        }

        let mod1Strings: [String] = configurationValueForKey(.mod1)!
        let mod2Strings: [String] = configurationValueForKey(.mod2)!

        modifier1 = modifierFlagsForStrings(mod1Strings)
        modifier2 = modifierFlagsForStrings(mod2Strings)
    }

and this one in the AppDelegate:

    private func presentDotfileWarningIfNecessary() {
        let shouldWarn = !UserDefaults.standard.bool(forKey: "disable-dotfile-conflict-warning")
        if shouldWarn && UserConfiguration.shared.hasCustomConfiguration() {
            let alert = NSAlert()
            alert.alertStyle = .warning
            alert.messageText = "Warning"
            alert.informativeText = "You have a .amethyst file, which can override in-app preferences. You may encounter unexpected behavior."
            alert.showsSuppressionButton = true
            alert.runModal()

            if alert.suppressionButton?.state == .on {
                UserDefaults.standard.set(true, forKey: "disable-dotfile-conflict-warning")
            }
        }
    }

You've also said it before (in https://github.com/ianyh/Amethyst/issues/331#issuecomment-148201528) that the configuration file overrides the preferences in GUI. Is creating a dotfile already possible? If so, I think a guide on creating the dotfile would solve a lot of problems. (I don't know how to create the dotfile. Otherwise, I would have already updated the README.md file, and created a pull request.)

Also, I would appreciate it if you could tell me which classes are relevant to implementing the import/export functionality.

martin-braun commented 1 year ago

I tried to bypass this limitation by hard-linking $HOME/Library/Preferences/com.amethyst.Amethyst.plist ~/Sync/config/Amethyst/com.amethyst.Amethyst.plist but Amethyst will not modify the file but in-fact replace it, whenever your configuration changes.