- Делаем так, чтобы терминал летал (часть 1)
- C чего стоит начать?
- А что не так с Gnome-terminal?
- Скорость
- Функциональность и использование памяти
- Решение проблемы
- Hyper
- Alacritty
- Конфигурация
- Пишем свою конфигурацию
- Hyper terminal mac os
- Extensions
- Keymaps
- Default keymaps:
- Configuration
- Config location
- Extensions API
- Module loading
- Notice
- Plugins location
- Decorating components
- Actions and Effects
- The underlying terminal
- Additional APIs
- Example theme: Hyperyellow
- Example extension: Hyperpower
Делаем так, чтобы терминал летал (часть 1)
Одним утром, работая в терминале, я задумался о том, что мой эмулятор терминала недостаточно быстрый и удобный, поэтому решил искать альтернативу старику gnome-terminal. Облазив половину интернета, а также репозитории с dotfile’ами, я нашёл достойную замену, и готов рассказать и показать как перейти с надоедливого gnome-terminal (который к тому же и медленный) на более новые эмуляторы терминала.
C чего стоит начать?
Первое, что я усвоил за 3 года работы на Linux — не пытайтесь написать все конфиги сами. Рук не хватит. В наше время каждая программа имеет свой собственный формат конфигурации будь-то .json, .cson, .vimrc, и так далее. Написать всё под себя, не пытаясь ничего перенять у других — пытка для вашего ума. Инструменты созданы (в основном) для того чтобы на них работать, а не всю жизнь их настраивать.
А что не так с Gnome-terminal?
Лично мне не нравится в нём многое: внешний вид, скорость, функциональность, время подгрузки оболочки. Мне терминал нужен для того, чтобы редактировать мелкие скрипты, иногда с мультиплексором. Я часто открываю и закрываю терминал, поэтому он должен прогружаться быстро. Также я использую Vim, как основной редактор, так что он должен быть полностью совместим с новым эмулятором терминала.
Скорость
Давайте посмотрим сколько времени требуется каждой консоли для выведения всех символов от 1 до 1,000,000 (шрифты везде одинаковые, так что погрешность времени прогрузки шрифта ± одинакова.
Функциональность и использование памяти
В Gnome-terminal банально нет копирования при выделении мышью, при создании нового экземпляра этот монстр жрёт плюс 20 мегабайт памяти только на создание нового окна.
При включении zsh при старте, эмулятор gnome’a долго его грузил, что для меня уже недопустимо.
Решение проблемы
Облазив некоторые ресурсы (ссылки на которые будут приведены в конце), я понял что gnome-terminal никуда не годится. Мне нужен продуктивный эмулятор терминала, который можно настроить так, чтобы он буквально понимал меня с полуслова. Также терминал должен быстро прогружать связку tmux+zsh.
Hyper
Hyper — эмулятор терминала, который построен на веб-технологиях. Его можно видоизменять с помощью стилей CSS. Он расширяемый и быстрый.
Уже настроенный Hyper
Alacritty
Alacritty — эмулятор терминала, который считается самым быстрым (по заявлению разработчика). Его работа ускоряется за счёт видео карты, он умеет выдерживать большие нагрузки (как видно, он даже с включенным tmux + zsh справился быстрее, нежели gnome + zsh)
Уже настроенный Alacritty
Конфигурация
Конфигурацию я выложил на Github по ходу того, как писал (и пишу) её, а также переводил, если брал у кого-то кусочки или брал примеры из документации. По своему усмотрению вы сами можете твикать всё как захотите. Не стесняйтесь делать pull-запросы, если у вас есть предложения. Моя цель — собрать удобную конфигурацию, которая бы смогла удовлетворить почти всех, а также с помощью одного скрипта, программист мог спокойно взять и начать работать, а не находится в поисках «где там я свою конфигурацию потерял».
Также в репозитории приложены два файла fastconfig.sh и fastconfig_arch.sh. 1-й для Debian/Ubuntu, второй для Arch/Manjaro.
Пишем свою конфигурацию
Я начну с Alacritty.
В следующей части проделаем то же самое с XTerm и Hyper. А также настроим Tmux и Vim.
Источник
Hyper terminal mac os
The goal of the project is to create a beautiful and extensible experience for command-line interface users, built on open web standards. In the beginning, our focus will be primarily around speed, stability and the development of the correct API for extension authors.
In the future, we anticipate the community will come up with innovative additions to enhance what could be the simplest, most powerful and well-tested interface for productivity.
Extensions
Extensions are available on npm. We encourage everyone to include hyper in the keywords field in package.json .
Then edit .hyper.js and add it to plugins
Hyper will show a notification when your modules are installed to .hyper_plugins .
Keymaps
All command keys can be changed. In order to change them, edit .hyper.js and add your desired change to keymaps .
Then Hyper will change the default with your custom change.
Example: ‘window:devtools’: ‘Cmd+Alt+O’
Default keymaps:
Configuration
Config location
/Library/Application Support/Hyper/.hyper.js
/.config/Hyper/.hyper.js
/.hyper.js still supported, but will be ignored, if config in application directory present. Otherwise it will be moved to the application directory at first run.
The config object seen above in .hyper.js admits the following
Property | Default | Description |
updateChannel | «stable» | The update channel to receive updates from |
fontSize | 12 | The default size in pixels for the terminal |
fontFamily | «Menlo, DejaVu Sans Mono, Lucida Console, monospace» | The font family to use with optional fallbacks |
uiFontFamily | «-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, . « | The font family to use for the UI with optional fallbacks |
fontWeight | «normal» | The default font weight: «normal» or «bold» |
fontWeightBold | «bold» | The font weight for bold characters: «normal» or «bold» |
cursorColor | «rgba(248,28,229,0.8)» | The color of the caret in the terminal |
cursorAccentColor | «#000» | The text color under BLOCK cursor |
cursorShape | «BLOCK» | The shape of the caret in the terminal. Available options are: ‘BEAM’, ‘UNDERLINE’, ‘BLOCK’ |
cursorBlink | «false» | If true, cursor will blink |
foregroundColor | «#fff» | The color of the main text of the terminal |
backgroundColor | «#000» | The color and opacity of the window and main terminal background |
selectionColor | «rgba(248,28,229,0.3)» | The background color/opacity of the text selection in terminal |
borderColor | «#333» | The color of the main window border and tab bar |
css | «» | Custom CSS to include in the main window |
padding | «12px 14px» | CSS padding values for the space around each term |
colors | A list of overrides for the color palette. The names of the keys represent the «ANSI 16», which can all be seen in the default config. | |
shell | «» | A path to a custom shell to run when Hyper starts a new session |
shellArgs | «[‘—login’]» | An array of shell arguments |
env | An object of environment variables to set before launching shell | |
windowSize | [540, 380] | The default width/height in pixels of a new window |
scrollback | 1000 | The number of rows to be persisted in terminal buffer for scrolling |
copyOnSelect | false | If true, selected text will automatically be copied to the clipboard |
quickEdit | false | If true, on right click selected text will be copied or pasted if no selection is present (true by default on Windows) |
defaultSSHApp | true | If true, Hyper will be set as the default protocol client for SSH |
modifierKeys | Change the behaviour of modifier keys to act as meta key | |
showHamburgerMenu | true on Linux/Windows, false on macOS | Change the visibility of the hamburger menu. Available options are: true, false |
showWindowControls | «» | Change the position/visibility of the window controls. Available options are: true, false, «left» |
Extensions API
Extensions are universal Node.js modules loaded by both Electron and the renderer process.
The extension system is designed around composition of the APIs we use to build the terminal: React components and Redux actions.
Instead of exposing a custom API method or parameter for every possible customization point, we allow you to intercept and compose every bit of functionality!
The only knowledge that is therefore required to successfully extend Hyper is that of its underlying open source libraries.
You can find additional details about plugin development in the Hyper repository.
Your module has to expose at least one of these methods:
Method | Invoked from | Description | |||||
onApp | Electron |
app | The electron app. |
Invoked when each window is created. If a plugin reloads, it’s invoked again with the existing windows.
window | An electron BrowserWindow . |
Invoked when a plugin is removed by the user.
app | The electron app. |
v0.5.0+. Allows you to decorate the user’s configuration.
Useful for themeing or custom parameters for your plugin.
config | The config object |
v0.7.0+. Allows you to decorate the user’s environment by returning a modified environment object.
environment | The environment object |
Invoked with the Electron’s Menu template. If a plugin reloads, it’s called again and the menu is refreshed.
menu | The menu template object |
Allows you to decorate Electron’s BrowserWindow options when a new window is created.
options | The BrowserWindow options object. |
Invoked when a plugin is first loaded or subsequently reloaded in each window.
window | The window object |
A custom Redux middleware that can intercept any action. Subsequently we invoke the thunk middleware, which means your middleware can next thunks.
reduceSessions
reduceTermGroups
A custom reducer for the ui , sessions or termgroups state shape.
state | The Redux state object |
action | The action object |
Passes down props from to the component. Must return the composed props object.
parentProps | Props form the parent component. |
props | The existing properties that will be passed to the component. |
Passes down props from to the component. Must return the composed props object.
uid | Tab / Term uid |
parentProps | Props form the parent component. |
props | The existing properties that will be passed to the component. |
Passes down props from to the component. Must return the composed props object.
uid | TermGroup uid |
parentProps | Props form the parent component. |
props | The existing properties that will be passed to the component. |
Passes down props from to the component. Must return the composed props object.
uid | Term uid |
parentProps | Props form the parent component. |
props | The existing properties that will be passed to the component. |
mapTermsState
mapHeaderState
mapNotificationsState
A custom mapper for the state properties that container components receive. Note that for children components to get these properties, you have to pass them down using the corresponding methods (like getTermProps ).
Must return an extended object of the map passed.
state | The Redux global state |
map | The existing map of properties that will be passed to the component. |
mapTermsDispatch
mapHeaderDispatch
mapNotificationsDispatch
A custom mapper for the dispatch properties. Must return an extended object of the map passed.
dispatch | The Redux dispatch function |
map | The existing map of properties that will be passed to the component. |
decorateNotifications
decorateNotification decorateHeader
decorateTabs
decorateTab decorateTerms
decorateTermGroup
decorateSplitPane
decorateTerm
Invoked with the React Component to decorate. Must return a Higher Order Component.
Hyper | The React Component constructor. |
env | A collection of useful module references for building components. See below |
Module loading
The user can hot-load and hot-reload plugins by pressing Command + R (refresh). Please strive to make plugins that don’t require a complete restart of the application to work.
Notice
Plugins affecting the `BrowserWindow` will the effect on new windows after hot-reload.
In the future we might do this automatically.
When developing, you can add your plugin to .hyper_plugins/local and then specify it under the localPlugins array in .hyper.js . We load new plugins:
- Periodically (every few hours)
- When changes are made to the configuration file ( plugins or localPlugins )
- When the user clicks Plugins > Update all now
The process of reloading involves
- Running npm prune and npm install in .hyper_plugins .
- Pruning the require.cache in both electron and the renderer process
- Invoking on* methods on the existing instances and re-rendering components with the fresh decorations in place.
Plugins location
/Library/Application Support/Hyper/.hyper_plugins
/.config/Hyper/.hyper_plugins
Note: plugins at
/.hyper_plugins still supported, but will be ignored, if plugins in application directory present. Otherwise they will be moved to the application directory at first run.
Note: on the main process, plugins are registered as soon as possible (we fire onLoad ). On the browser, it’s up to the user to trigger their load by pressing command+R. We put the user in control of the loading in this way to prevent them from losing critical work by extensions that reset state or don’t preserve it correctly.
Decorating components
We give you the ability to provide a higher order component for every piece of the Hyper UI.
Its structure is as follows:
All the decorate* methods receive the following references in an object passed as the second parameter:
React | The entire React namespace. |
notify | |
Notification | The Notification component in case you want to re-use it. |
All the components accept the following two properties to extend their markup:
customChildren | An array of Element or a single Element to insert at the bottom of the component. |
customChildrenBefore | The same as the above property, but inserted as the first child element(s) of the component. |
Your higher order component can supply a onDecorated property to the decorated component to get a reference to its instance.
Your Term higher order component can supply an onCursorMove handler property that be called when cursor has moved with an object parameter representing its relative position to Term origin:
x | Horizontal position in pixels |
y | Vertical position in pixels |
width | Cursor width in pixels |
height | Cursor height in pixels |
col | Horizontal position in columns |
row | Vertical position in rows |
We encourage you to maintain compatibility with other decorators. Since many can be set, don’t assume that yours is the only one.
For example, if you’re passing children, compose potential existing values:
Or if you use onDecorated property
Actions and Effects
All the Redux actions are available for you to handle through your middleware and reducers. For an example, refer to the Hyperpower reference plugin.
Side effects occur in two fundamental forms:
- Some actions dispatch other actions based on state.
- Some actions do async work by communicating over the RPC channel to the main process
In all cases, the side effect is passed as the effect key in the action and later handled by our middleware.
This means that you can override, compose or completely eliminate effects! In other words, this is how you can change the default functionality or behavior of the app.
As an example, consider the action we use to increase the font size when you press Command+= :
The underlying terminal
Hyper achieves a lot of its speed and functionality thanks to the power of xterm.js
Additional APIs
The Electron app objects are extended with the following properties:
config | An Object with the config block from .hyper.js . |
plugins | An Object with helpers for plugins. |
getWindows | A Function that returns an Set of all the open windows. |
createWindow | A Function that will create a new window. Accepts an optional callback that will be passed as the new window’s init callback. |
Electron BrowserWindow objects are extended with the following parameters:
rpc | An EventEmitter that allows for communication with the window process. |
sessions | A Map of Session objects which hold the communication with each term’s pty.. |
Renderer windows are similarly extended with:
rpc | An EventEmitter that allows for communication with the window process. |
store | The Redux Store object. This allows access to dispatch actions or read the global state with getState . |
The rpc object is symmetrical between browser and renderer process. The API is the same as Node.js, with the exception that it only admits a single object as its parameters only:
Example theme: Hyperyellow
The following extension simply alters the config to add CSS and yellow colors! Here’s the code.
Themes are simply plugins! Only one hook, decorateConfig is needed:
I grabbed the class names by inspecting the term with Devtools, which you can trigger from View -> Toggle Developer Tools . When you do so, notice that some classes are automatically generated and followed by a random nonce (e.g.: term_13hv8io ). Ignore those: they change with every new window!
Notice the emphasis on playing nice with other extensions. Specifically, we create a new object, extend only the keys we are interested in, and we compose the CSS to preserve the user’s setting and that of other authors’:
Example extension: Hyperpower
The following extension renders particles as the caret moves:
Let’s walk through its code.
First, we intercept the Redux action SESSION_ADD_DATA . You can find the full list of actions in the repository.
Notice that we don’t re-dispatch the action, which means we never render the output of the command to the terminal. Instead, we dispatch an action of our own, which we grab in the uiReducer and later map:
We then want to decorate the component so that we can access the underlying caret.
However, is not a container that we can map props to. So we use getTermProps to pass the property further down:
The extension then returns a higher order component to wrap . Notice we pass the onDecorated property to access the base Term component and its DOM ref, and the onCursorMove property to use Hyper cursor API:
Источник