GithubHelp home page GithubHelp logo

reibitto / command-center Goto Github PK

View Code? Open in Web Editor NEW
99.0 3.0 12.0 1.44 MB

A CLI-based launcher and general productivity tool.

License: Apache License 2.0

Scala 96.25% AppleScript 0.86% Swift 0.43% PowerShell 0.15% Java 2.31%
zio scala functional-programming alfred launcher productivity cross-platform window-manager

command-center's Introduction

Command Center

Scala CI

A CLI-based launcher and general productivity tool.

What is it?

Command Center is used to launch applications, find files, control music playback, search the web, run one-off CLI commands, manage windows, and anything else you can imagine since it's customizable.

If you're familiar with tools like Alfred, Wox, ueli, Keypirinha, etc. you may already understand the concept. These tools already work great. Command Center aims to fill a slightly different niche though, targeting hackers/programmers who enjoy and are familiar with working in the command line.

Features/Goals

(Note: Command Center is still in active development. Some of these are still being worked on.)

  • Cross-platform (macOS, Windows, Linux)
  • Can be run purely from the command line, in both standalone and daemon modes.
  • Has its own terminal emulator that can be summoned with a hotkey (like a Quake console). Useful for running one-off commands when you're not already in a terminal window.
  • Focus on not being resource-heavy or draining battery. While Electron can do many things, it's not resource-friendly, which is one reason why Command Center doesn't use it.
  • Plugins are first-class. All the internal commands use the same plugin system a 3rd-party would use to integrate with Command Center. No scripting languages that only do a fraction of what the "real" thing can do.
  • Automatic language detection. For example, if you type Japanese text, you can open the Japanese version of Google, Wikipedia, etc. as opposed to the default (English) versions.

Example usage

recording

Finding files

Start typing the name of the file you're looking for. You can also use the following commands:

  • find filename - Find file by filename
  • in filename - Find file by its contents

Music controls

  • play - Start playing music (e.g. by default opens iTunes on macOS)
  • pause - Pause the current track
  • stop - Stop the current track
  • next - Switch to the next track in your playlist
  • previous - Switch to the previous track in your playlist
  • rate [1-5] - Rate the current track

Timer

If you want to start a simple countdown timer:

timer 15m -m "Call Sally"

This will pop up a notification after 15 minutes. Specifying a message is optional.

Suspend/resume process

You can suspend (toggle) a process by its PID with:

suspend 321

The suspend command also has a configurable suspendShortcut attribute that is a global shortcut. This is useful if you want to be able to pause applications that don't have a built-in pause feature, such as games. The idea for this feature came from Universal Pause Button.

Window Manager

Global hotkeys can be mapped to various window management actions. For example:

  • Minimize/maximize window
  • Center window
  • Move window to next/previous monitor
  • Cycle window location+size in each direction. For example, pressing win+alt+right the first time will move+resize the window to the right half of the screen. Pressing it again will resize it to 2/3 of the screen. And once more will be 1/3 of the screen. Then the cycle repeats.

Note: This feature currently only supports Windows. The goal is to support all OSes soon.

Calculator

You can use some built-in constructions and functions to quickly evaluate mathematical expressions:

  • numbers, e. g. 5, -2., +2.6
  • constants (case-insensitive):
    • pi
  • () (parentheses for grouping)
  • symbolic operators:
    • +, -, *, /, % (modulo), ^ (power), e. g. 5 * (3 - 4/2) ^ 2 % 3
    • ^ has a higher precedence than any other symbolic operators, all of which has equal precedence
  • functions (case-sensitive; have a higher precedence than symbolic operators):
    • one-parametric: ! (factorial), acos, asin, atan, ceil, cos, cosh, exp, floor, ln, round, sin, sinh, sqrt, tan, tanh, toDeg (radians -> degrees), toRad (degrees -> radians)
    • two-parametric: atan2, choose (Newton's binomial), gcd (greatest common divisor), hypot (square root of x^2 + y^2), log, random
    • multi-parametric: max, min

Whitespaces between parts of an expression are ignored.

One-parametric functions can be written in two forms:

  • separated by spaces for simple parameters (number/constant): sin PI, sqrt 16
  • with parameters enclosed in parentheses for both simple and more complex expressions: sin(PI / 2), sqrt(9).

Two- or multi-parametric functions can be written in three forms: gcd 20 16, or gcd 20; 16, or gcd(20; 16) (; is here the configurable parameterSeparator).

choose has also an infix form: 6 choose 3.

max/min can have more than two parameters: max 0 5 (-6/4).

random has 3 flavours:

  • random (zero-parametric): a random number from [0, 1]
  • random a b (two-parametric): a random number from [a, b]
  • random int a b (two-parametric): a whole random number from [a, b]

Constraints:

  • for n choose r, both n and r have to be whole and non-negative, n >= r
  • for n!, n has to be whole and non-negative
  • for gcd(a, b), both a and b have to be whole

Parameters

As different countries may have their own traditions for writing numbers (one of the obvious differences being the decimal separator — dot vs. comma), some of the most important parameters are determined locale-specifically or can be overriden in application.conf if needed:

{
  type: "CalculatorCommand"
  decimalSeparator: ","
  groupingSeparator: "_"
  parameterSeparator: ";"
  groupingSize: 3
  groupingUsed: true
  maximumFractionDigits: 10
}

These settings apply both for parsing and displaying. parameterSeparator can be used with a multi-parametric function. All other parameters correspond to properties of DecimalFormat/DecimalFormatSymbols of the same name. Any of them can be omitted, their default values are then locale-specific. For the parameterSeparator the default is ;.

List available operators/functions

Type in calculator functions to see the full list of available operators and functions.

List available configuration parameters

Type in calculator parameters to see the full list of available configuration parameters for application.conf.

Installation

At the moment there is no simple "1-step install". You need to compile and generate an executable yourself (or run directly from SBT).

application.conf is needed to run Command Center. The following locations are searched (in order):

  1. COMMAND_CENTER_CONFIG_PATH (if defined)
  2. ~/.command-center/application.conf
  3. ./application.conf

Important note: For the pop-up emulator window to activate and come to the front properly on macOS you need to make sure you place the cc-tools executable in the proper location. Either place it in ~/.command-center/cc-tools or define the COMMAND_CENTER_TOOLS_PATH environment variable if you want to specify a custom location.

Installing built-in optional plugins

Command Center comes with some optional plugins. These plugins are optional because they're either too niche or bring in heavier dependencies that normal users wouldn't need. Currently there are:

Ject dictionary plugin

A real-time, offline dictionary plugin (currently only supports Japanese). This is based on Ject. You'll need to build the Lucene index first as described in the README. Then specify the command in application.conf like this:

{
  type: "commandcenter.ject.JectJaCommand$",
  dictionaryPath: "/path/to/ject/data/lucene/word-ja"
}

Kanji plugin

A tool for searching kanji by parts. This plugin also uses Ject and requires a Lucene index for the kanji dictionary to be created first.

Some example queries:

  • kanji 日月: 明, 朝, 晴, 腸, 盟, etc.
  • kanji 大山可: 崎, 嵜, etc.
  • kanji キヒ日: 指, 掲, etc.
  • kanji B東: 陳

As you can see, there are some "shortcuts" for convenience if you don't know how to type a certain radical. These can be found here.

To install the Kanji plugin, you need the following in application.conf:

{
  type: "commandcenter.ject.KanjiCommand$",
  dictionaryPath: "/path/to/ject/data/lucene/kanji"
}

Kanji stroke order plugin

Used to bring up the stroke order of kanji. This relies on having Kanji stroke order font installed. Also it requires using the terminal emulator as native CLI clients rarely allow changing the default font. Usage is stroke 漢字. The config looks like this:

{type: "commandcenter.strokeorder.StrokeOrderCommand$"}

Enabling the plugins

You can either set an sbt option or environment variable to enable the above plugins:

export COMMAND_CENTER_PLUGINS="stroke-order-plugin, ject-plugin"

or start up sbt like this:

sbt -Dcommand-center-plugins="ject-plugin, stroke-order-plugin"

To enable all plugins, you can also use *.

Development

Command Center mainly uses Scala with a strong focus on typed functional programming (via ZIO). Types make developing plugins a much more pleasant experience as you get feedback quicker and features are more discoverable. Writing a command is as simple as writing a single class like so.

Once you start SBT, you should be presented a list of common commands. For example:

  • ~compile - Compile all modules with file-watch enabled
  • cli/run - Run Command Center CLI client (interactive mode by default). Particularly useful for local development.
  • emulator-swing/run - Run the Command Center emulated terminal (cmd+space to summon terminal emulator)
  • emulator-swing/assembly - Create an executable JAR for running in terminal emulator mode
  • cli/assembly - Create an executable JAR for running command line utility
  • cli/graalvm-native-image:packageBin - Create a native executable of the CLI client

Configuration

All commands can be configured. You can disable any core command, rename them, change their options, add new commands, create aliases (useful for shortening argument passing), and so on.

Configuration format

Commands and options are configured with a single HOCON configuration file. To see an example, take a look at application.conf.

Creating your own plugins

If you created a plugin and it's general-purpose and doesn't bring in extra dependencies, feel free to create an issue or PR to get the command into Command Center's core commands. If not (or if you'd prefer to maintain the plugin yourself), you can create your own separate repository to host it. If you let me know, I can add it to a list of external plugins.

Eventually the goal is to make installing external plugins as simple as running a single install command. See this issue here. Until then, it's a matter of dropping your jar file in the plugins folder and restarting the app. For more details on external plugins, refer to the plugins readme.

Contributing

There are a lot of issues marked as "good first issue" here. Feel free to take any that interest you. I'd also appreciate any help for OS-specific features. Help with Windows and Linux would be great since I've mainly been focusing on macOS for now.

Writing your own commands is a great way to begin learning ZIO. Each command can be developed, tested, and run in isolation. For more help with ZIO, the Discord channel is a great place to ask questions.

command-center's People

Contributors

davewm avatar duester avatar gkhotyan avatar reibitto avatar scala-steward avatar tuleism avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

command-center's Issues

Add shortcut support for Commands

You should be able to set shortcuts for your commands (for example, cmd+G for Google, etc). If a single shortcut is bound to multiple commands, select the one with the highest score.

This is useful if you would rather not scroll through the results (or type more than you have to) for common operations.

Add tests for core functionality

There are no tests right now and that makes it really easy to break things. "Add tests" is too broad of an issue, so for now the focus should probably be the Command.search functionality. The function doesn't require a broad set of dependencies, so it should be pretty easy to set up tests for. Just create a Vector of arbitrary commands and aliases and then pass in a search string and make sure the results are correct.

Clipboard manager

There's a lot that could be done here. But I was thinking about having a clipboard history, and possibly storing it as a tree-like structure could be cool. Might want to leverage existing solutions for this?

Also, there should probably be a way to clear the history. And perhaps something to prevent storing sensitive data in the history.

Package/distribution file (.app/.exe/etc files)

I haven't done this before with a JVM app yet, but the daemon project should be packaged into a single executable like .app for macOS, .exe for Windows, and so on. The daemon project is a GUI application.

The cli-client on the other hand is fine to be a simple binary executable file. Ideally we distribute with homebrew for Mac and so on for other operating systems. Or just a plain install script.

Maps command

Opens Google Maps (or configurable alternatives). Should also support directions, something like from X to Y, directions X to Y, etc.

LocalIPCommand for other OSes

Currently, to get local IP address, we use:

localIP <- PCommand("ipconfig", "getifaddr", "en0").string.bimap(CommandError.UnexpectedException, _.trim)

It works for macOS, but for Linux the command can vary based on the distro, not to mention Windows. For example, I'm using Manjaro and the default command to list addresses is ip a, which then needs some command line magic to extract the IP address.

We can use Java/Scala to get this information. This seems to work with my box (multiple interfaces, running together with docker and VMs)

val interfaces = NetworkInterface.getNetworkInterfaces.asScala.toList
interfaces.filter { interface =>
  !interface.isLoopback && !interface.isVirtual && interface.isUp
}.flatMap { interface =>
  interface.getInetAddresses.asScala.collect {
    case address: Inet4Address => interface.getDisplayName -> address.getHostAddress
  }
}

Fix cli-client native-image build

Graal native-image for the cli-client was working until async-http-client-backend-zio was added. It has to do with the netty dependency. I tried fixing it, but no luck so far. Making netty work with native-image appears to be super complicated.

If this can't be fixed, maybe we should try a different backend. But there doesn't appear to be a compatable ZIO backend at the moment. Maybe we can add one to sttp. Such as a OkHttpZIOBackend?
https://sttp.softwaremill.com/en/latest/backends/summary.html

Add timeout to commands

If a command is taking too long for whatever reason, we should probably cancel it (with a configurable timeout) to minimize delay and save resources.

There aren't many commands that have the potential to run too long yet, but this feature is something that will see more use in the future. Currently there's only 1 command that makes an HTTP request.

Possible Calculator enhancements

  • Might want to display integer values as 1 instead of 1.0 and so on.
  • Decimal separator could be based on the user's locale. For example, some countries use , instead of .
  • Similar to the above, but also one for grouping separator.
  • Maybe even make these formatting options a config value.
  • Additional functions: log2, ln, ceil, floor
  • Is there value in using BigDecimal instead of Double as the base type?

Menubar (system tray) support

This probably depends on the OS, but it would be nice to be able to not show the app's icon in the dock/taskbar since the daemon is basically always running. Apps like Alfred tend to show up only in the menubar (system tray for Windows).

Design better search execution model

The multiple events in Command are a bit awkward right now:

  • inputPreview
  • keywordPreview
  • prefixPreview
  • argsPreview

It also has the issue where if you implement multiple of these in a single command, things might be executed multiple times for a single input (assuming you don't early-exit).

I think maybe all of these could be combined into a single ADT and then have 1 def preview(...) which would replace the other 4. Or if not an ADT, one SearchInput class that you can parse into these different cases with helper methods.

Dictionary command

I'm imagining the usage being like "define WORD". Some operating systems have built-in dictionaries (like macOS). I'm not sure if those are usable or not. Or do we have to use an online API instead?

Make commands more discoverable

I was thinking it might be nice if more of the available commands showed up at the bottom of the results list (i.e. giving it a low score) rather than hiding them completely. Though maybe this should be a configurable option in case you want the results pane to be as small as possible.

Allow multiple output for a single command

Currently, one command can only shows only one output, even though it may have a list:

        .sortBy(_.score)(Ordering.Double.TotalOrdering.reverse)
        .distinctBy(_.source)

One possible way to do it is:

  • groupBy(_.source).
  • Sort by score descending, using the highest score within a group.
  • If the group with highest score has multiple items, show them all. Otherwise, keep the same behavior.

WDYT?

Unit converter

For converting things like kg/lbs, cm/feet, etc.

You can take a look at how TemperatureCommand is implemented. We could generalize that so it works with all kinds units, not just temperature.

If there are 3rd-party JVM solutions for this, that would also be an option. We would then just need to wrap it.

Prevent duplicate results from showing up

This is rare, but it can happen in certain cases. I think the cause is when you set an alias that is the prefix of that same command. For example:

duplicate

This is because the config is:

aliases {
  "epoch" = ["epochunix", "epochmillis"]
}

Both the alias and the prefix of the command is being matched.

Improve UX when hitting enter quickly

Right now it's possible to type something really fast and hit enter and before the results have populated. This should be addressed in some way. A couple of things:

  • The debounce duration should be configurable (and setting it to 0 should disable it). Also, it's possible the default duration is too long.
  • When hitting enter, perhaps it should be queued up rather than running instantaneously.

The thing is, this is a delicate issue that's hard to get right. This will get trickier once #4 is addressed. We want to try to avoid issues where you type something, get some results, and then just as you hit enter a new result (one that you didn't want/expect) popped up and took its place for the highest score causing you to run a command you didn't intend to. For anyone who has tried using Spotlight, I'm sure you know exactly what I'm talking about. 😛

Add command history

Similar to how you can scroll up and down in your history in the command line, you should be able to do the same in Command Center.

Things to keep in mind:

  • Up/down arrow keys are already used for scrolling through results. We'll likely need to come up with different key combinations for this. Of course making it configurable.
  • ctrl+R recursive search
  • Might want to create a cache/persistent storage ZIO Reader/Environment as part of this issue. Edit: The cache part of this is done now.

External plugin install/uninstall command

I want to be able to install external plugins with a single command like install plugin-name.

I think we should maintain a list of "verified" plugins. But you should also be able to install unverified plugins by URL and file path. Should probably pop up a security warning for the latter case though.

This is a difficult task and I don't recommend tackling it just yet. But it's something that I eventually want.

Escape/unescape encode/decode command

Each one should be its own Command object, but we can also add them to the general encode alias that maps to all of them.

Some that I had in mind:

  • URL encoder/decoder
  • Base 64 encoder/decoder
  • HTML encoder/decoder
  • Java/Scala/etc string escape/unescape
  • JSON escape/unescape
  • CSV escape/unescape
  • Unicode escape/unescape (U+0000 0x0000 formats)

And any other useful ones that you can think of.

Timezone converter

Idea: 6pm ET = GMT will show 7pm. We can start with --time {time} --from {timezone} --to {timezone}.

  • If from is omitted, take current time zone, or a configured one. Same for to.
  • If time is omitted, take now().

Windows file search and open file/application support

I'm not too familiar with Windows and how good the default Windows search works (and whether you can use their internal API in the first place). But if it's not great, perhaps using the Everything tool for indexing would be a good option. It seems like it's a common choice among Windows application launchers.

Calculator command

You should be able to type math expressions like 52 + (21*672) and so on and it could show the result right there in the preview window. Support for n choose r, factorial, and all kinds of miscellaneous functions would be nice too. I find myself needing those a lot.

Add Google Translate Command

Here's a reference to one implementation:
http://www.wox.one/plugin/60

In addition to this, there is an opportunity to integrate the auto language detection (which I barely started here). It might also help to have a config option for the languages you use (or are learning) and use that to improve auto-detection. For example, if I have languages = ["en", "ja"] set then it should automatically know to translate to English by default if I type Japanese text.

Calendar command

It would be nice to have a command for adding calendar events easily. I haven't thought about what the interface should look like, but something that is flexible might be best. I think I'd like to be able to write stuff like "John's welcome party @ 9pm" or something and it would add it to my configured calendar.

But if that's too difficult, a command line interface could work too. Something like:
cal --date tomorrow --time 19:00 Welcome Party

Or whatever else anybody else can think of.

Add proper multi-monitor support

You should be able to specify which screen you want the pop-up terminal to show up on. This would go in the DisplayConfig class.

Render each command asynchronously

Right now when the user inputs text, all commands are run against that text and the results are collected in one go. This means if there's 1 slow command, it'll hold up the results from rendering until it's done.

What really should be done is to make each command result render independently. To make this efficient, debounce it so that we don't call render a ridiculous amount of times. Most commands will complete within a couple of milliseconds anyway, so only a small waitTime on the debounce should be needed.

Create KeyboardShortcut class

For a few reasons:

  • To not bring in a Swing dependency to core
  • For better parsing of keyboard shortcuts. For example, allowing to specify win/windows key instead of meta. And to allow more variations like ctrl vs. control and so on. And maybe even support symbols like ⌘ (for Mac).
  • Useful for #31. This would unify the keyboard shortcut format between Swing and lanterna.

Once that's done, change the configs like KeyboardConfig(openShortcut: String) to KeyboardConfig(openShortcut: KeyboardShortcut)

Randomize MAC address command

Reference: http://www.packal.org/workflow/random-mac

Just use rmac to generate and apply a new MAC address. This can be useful when traveling, using free wifi, or troubleshooting a router. If you need an interface other than en0, just edit the script, it's very simple.

We can make the interface part an arg. But en0 is a fine default.

Graal native image support for daemon

Creating Graal native images are tricky depending on what features you're using. Creating one for daemon is probably not doable until some issues like Swing compatibility are resolved. For example: oracle/graal#664

A native-image for cli-client is more realistic and I got that mostly working. There are limitations though. For example, loading external plugins requires reflection and that doesn't gel well with native-image because of reflection limitations. I'm not sure if there's a way to make a plugin system work with native-image. This needs some investigation.

Emoji search command

A command for searching emojis by name and then copying it into your clipboard.

All command names should be customizable

Right now commandNames is hardcoded inside the class itself:

val commandNames: List[String] = List("exit", "quit")

It would be better if it were a field of the case class instead.

Then each Decoder instance would need to change to look for commandNames in application.conf.

It would be fine to keep the default names if the field is left off completely. The point of this change is that it gives you the capability to rename anything.

Maven search command

To be able to quickly pull the latest version of a dependency into your clipboard and so on. Might be nice to also have a view that shows the transitive dependencies.

Windows Graal native image support

I gave this a try too, but ran into these blockers:
oracle/graal#1870
oracle/graal#1327

The next release looks like it'll include the fix. But even if you get passed that one, there might be other blockers lurking. Can't know until we try.

Also, Windows support for native-image seems very experimental right now. Just configuring everything was a huge pain for me. We might want to hold off on this issue until the Windows support is more stable. But if anybody wants to try tackling it anyway, that's fine with me.

Currency converter

This is self-explanatory. The only thing is which API do we use for this? Is there something that's free?

Password manager integrations

Might want to separate this issue out for each password manager that we want to support, but basically I'd like to support the most common ones.

Add better error handling

Right now I don't print errors because it interferes with the UI (at least for CLI mode). We need a logger that is aware of whether it's in CLI mode or not. If it's not, then print to the console. Otherwise print to a file I guess?

Another idea is to store errors in a ring buffer and have a Command for viewing these errors.

Spotify command

Playback controls for Spotify.

I imagine this will also need a cache ZIO Reader so that you can store whatever auth token/session ID (to prevent re-authing for each command).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.