feat: export image of the current theme
10
.github/workflows/docs.yml
vendored
|
@ -13,10 +13,20 @@ jobs:
|
||||||
uses: actions/checkout@v2.3.1
|
uses: actions/checkout@v2.3.1
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v2
|
||||||
|
with:
|
||||||
|
go-version: 1.16
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd src
|
||||||
|
go build -o docs/oh-my-posh
|
||||||
|
cd ..
|
||||||
- name: Install and Build 🔧
|
- name: Install and Build 🔧
|
||||||
run: |
|
run: |
|
||||||
cd docs
|
cd docs
|
||||||
npm install
|
npm install
|
||||||
|
npm run themes
|
||||||
npm run build
|
npm run build
|
||||||
- name: Deploy 🚀
|
- name: Deploy 🚀
|
||||||
uses: JamesIves/github-pages-deploy-action@3.6.2
|
uses: JamesIves/github-pages-deploy-action@3.6.2
|
||||||
|
|
3
.gitignore
vendored
|
@ -155,3 +155,6 @@ bin/
|
||||||
Output/
|
Output/
|
||||||
*.sha256
|
*.sha256
|
||||||
*.7z
|
*.7z
|
||||||
|
|
||||||
|
# images
|
||||||
|
*.png
|
||||||
|
|
25
.vscode/launch.json
vendored
|
@ -1,7 +1,4 @@
|
||||||
{
|
{
|
||||||
// Use IntelliSense to learn about possible attributes.
|
|
||||||
// Hover to view descriptions of existing attributes.
|
|
||||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
|
@ -42,6 +39,28 @@
|
||||||
"--shell=pwsh",
|
"--shell=pwsh",
|
||||||
"--config=${workspaceRoot}/themes/jandedobbeleer.omp.json"
|
"--config=${workspaceRoot}/themes/jandedobbeleer.omp.json"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Export PNG",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"program": "${workspaceRoot}/src",
|
||||||
|
"args": [
|
||||||
|
"--export-png",
|
||||||
|
"--shell=shell",
|
||||||
|
"--rprompt-offset=40",
|
||||||
|
"--cursor-padding=15",
|
||||||
|
"--config=${workspaceRoot}/themes/jandedobbeleer.omp.json"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Theme export",
|
||||||
|
"cwd": "${workspaceFolder}/docs",
|
||||||
|
"program": "${workspaceRoot}/docs/export_themes.js",
|
||||||
|
"console": "integratedTerminal"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
54
docs/docs/share.mdx
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
---
|
||||||
|
id: share
|
||||||
|
title: Share
|
||||||
|
sidebar_label: 📸 Share
|
||||||
|
---
|
||||||
|
|
||||||
|
import Tabs from "@theme/Tabs";
|
||||||
|
import TabItem from "@theme/TabItem";
|
||||||
|
|
||||||
|
You can export your prompt to an image which you can share online. You have the ability to align it correctly and add your name for credits too.
|
||||||
|
|
||||||
|
:::warning
|
||||||
|
Some glyphs aren't rendered correctly, that's not you but the limitations of the renderer. Depending on your config, you might have to tweak
|
||||||
|
the output a little bit.
|
||||||
|
:::
|
||||||
|
|
||||||
|
<Tabs
|
||||||
|
defaultValue="powershell"
|
||||||
|
values={[
|
||||||
|
{ label: 'powershell', value: 'powershell', },
|
||||||
|
{ label: 'others', value: 'others', },
|
||||||
|
]
|
||||||
|
}>
|
||||||
|
<TabItem value="powershell">
|
||||||
|
|
||||||
|
You can make use of the `Export-PoshImage` function to export your current theme configuration.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Export-PoshImage -CursorPadding 50
|
||||||
|
```
|
||||||
|
|
||||||
|
There are a couple of parameters you can use to tweak the image rendering:
|
||||||
|
|
||||||
|
- `CursorPadding`: spaces to add after the cursor indication (`_`)
|
||||||
|
- `RPromptOffset`: spaces to add **before** a block that's right aligned
|
||||||
|
- `Author`: the name of the creator, added after `https://ohmyposh.dev`
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
<TabItem value="others">
|
||||||
|
|
||||||
|
The oh-my-posh executable has the `--export-png` switch to export your current theme configuration.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
oh-my-posh --config ~/.mytheme.omp.json --export-png --cursor-padding 50
|
||||||
|
```
|
||||||
|
|
||||||
|
There are a couple of additional switches you can use to tweak the image rendering:
|
||||||
|
|
||||||
|
- `--cursor-padding`: spaces to add after the cursor indication (`_`)
|
||||||
|
- `--rprompt-offset`: spaces to add **before** a block that's right aligned
|
||||||
|
- `--author`: the name of the creator, added after `https://ohmyposh.dev`
|
||||||
|
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
|
@ -16,102 +16,6 @@ Once you're ready to swap to a theme, follow the steps described in [🚀Install
|
||||||
|
|
||||||
Themes with `minimal` in their names do not require a Nerd Font. Read about [🆎Fonts][fonts] for more information.
|
Themes with `minimal` in their names do not require a Nerd Font. Read about [🆎Fonts][fonts] for more information.
|
||||||
|
|
||||||
### [Agnoster]
|
|
||||||
|
|
||||||
[![Agnoster](/img/themes/agnoster.png)][Agnoster]
|
|
||||||
|
|
||||||
### [AgnosterPlus]
|
|
||||||
|
|
||||||
[![AgnosterPlus](/img/themes/agnosterplus.png)][AgnosterPlus]
|
|
||||||
|
|
||||||
### [Aliens]
|
|
||||||
|
|
||||||
[![Aliens](/img/themes/aliens.png)][Aliens]
|
|
||||||
|
|
||||||
### [Avit]
|
|
||||||
|
|
||||||
[![Avit](/img/themes/avit.png)][Avit]
|
|
||||||
|
|
||||||
### [DarkBlood]
|
|
||||||
|
|
||||||
[![DarkBlood](/img/themes/darkblood.png)][DarkBlood]
|
|
||||||
|
|
||||||
### [Emodipt]
|
|
||||||
|
|
||||||
[![Emodipt](/img/themes/emodipt.png)][Emodipt]
|
|
||||||
|
|
||||||
### [Fish]
|
|
||||||
|
|
||||||
[![Fish](/img/themes/fish.png)][Fish]
|
|
||||||
|
|
||||||
### [Honukai]
|
|
||||||
|
|
||||||
[![Honukai](/img/themes/honukai.png)][Honukai]
|
|
||||||
|
|
||||||
### [JanDeDobbeleer]
|
|
||||||
|
|
||||||
[![JanDeDobbeleer](/img/themes/jandedobbeleer.png)][JanDeDobbeleer]
|
|
||||||
|
|
||||||
### [Lambda]
|
|
||||||
|
|
||||||
[![Lambda](/img/themes/lambda.png)][Lambda]
|
|
||||||
|
|
||||||
### [Material]
|
|
||||||
|
|
||||||
[![Material](/img/themes/material.png)][Material]
|
|
||||||
|
|
||||||
### [ParaRussel]
|
|
||||||
|
|
||||||
[![ParaRussel](/img/themes/pararussel.png)][ParaRussel]
|
|
||||||
|
|
||||||
### [Powerlevel10k_Classic]
|
|
||||||
|
|
||||||
[![Powerlevel10k_Classic](/img/themes/powerlevel10k_classic.png)][Powerlevel10k_Classic]
|
|
||||||
|
|
||||||
### [Powerlevel10k_Lean]
|
|
||||||
|
|
||||||
[![Powerlevel10k_Lean](/img/themes/powerlevel10k_lean.png)][Powerlevel10k_Lean]
|
|
||||||
|
|
||||||
### [PowerLine]
|
|
||||||
|
|
||||||
[![PowerLine](/img/themes/powerline.png)][PowerLine]
|
|
||||||
|
|
||||||
### [RobbyRussel]
|
|
||||||
|
|
||||||
[![RobbyRussel](/img/themes/robbyrussel.png)][RobbyRussel]
|
|
||||||
|
|
||||||
### [Sorin]
|
|
||||||
|
|
||||||
[![Sorin](/img/themes/sorin.png)][Sorin]
|
|
||||||
|
|
||||||
### [Star]
|
|
||||||
|
|
||||||
[![Star](/img/themes/star.png)][Star]
|
|
||||||
|
|
||||||
### [Zash]
|
|
||||||
|
|
||||||
[![Zash](/img/themes/zash.png)][Zash]
|
|
||||||
|
|
||||||
[themes]: https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes
|
[themes]: https://github.com/JanDeDobbeleer/oh-my-posh/tree/main/themes
|
||||||
[fonts]: /docs/fonts
|
[fonts]: /docs/fonts
|
||||||
[replace-you-existing-prompt]: /docs/installation#3-replace-your-existing-prompt
|
[replace-you-existing-prompt]: /docs/installation#3-replace-your-existing-prompt
|
||||||
|
|
||||||
[Agnoster]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/agnoster.omp.json 'Agnoster'
|
|
||||||
[AgnosterPlus]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/agnosterplus.omp.json 'AgnosterPlus'
|
|
||||||
[Aliens]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/aliens.omp.json 'Aliens'
|
|
||||||
[Avit]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/avit.omp.json 'Avit'
|
|
||||||
[DarkBlood]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/darkblood.omp.json 'DarkBlood'
|
|
||||||
[Emodipt]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/emodipt.omp.json 'Emodipt'
|
|
||||||
[Fish]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/fish.omp.json 'Fish'
|
|
||||||
[Honukai]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/honukai.omp.json 'Honukai'
|
|
||||||
[JanDeDobbeleer]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/jandedobbeleer.omp.json 'JanDeDobbeleer'
|
|
||||||
[Lambda]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/lambda.omp.json 'Lambda'
|
|
||||||
[Material]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/material.omp.json 'Material'
|
|
||||||
[ParaRussel]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/ParaRussel.omp.json 'ParaRussel'
|
|
||||||
[Powerlevel10k_Classic]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/powerlevel10k_classic.omp.json 'Powerlevel10k_Classic'
|
|
||||||
[Powerlevel10k_Lean]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/powerlevel10k_lean.omp.json 'Powerlevel10k_Lean'
|
|
||||||
[PowerLine]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/powerline.omp.json 'PowerLine'
|
|
||||||
[RobbyRussel]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/robbyrussel.omp.json 'RobbyRussel'
|
|
||||||
[Sorin]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/sorin.omp.json 'Sorin'
|
|
||||||
[Star]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/star.omp.json 'Star'
|
|
||||||
[Zash]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/zash.omp.json 'Zash'
|
|
||||||
|
|
102
docs/export_themes.js
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
//jshint esversion:8
|
||||||
|
//jshint node:true
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const util = require('util');
|
||||||
|
const exec = util.promisify(require('child_process').exec);
|
||||||
|
|
||||||
|
const themesConfigDir = "./../themes";
|
||||||
|
const themesStaticDir = "./static/img/themes";
|
||||||
|
|
||||||
|
function newThemeConfig(rpromptOffset = 40, cursorPadding = 30, author = "") {
|
||||||
|
var config = {
|
||||||
|
rpromptOffset: rpromptOffset,
|
||||||
|
cursorPadding: cursorPadding,
|
||||||
|
author: author
|
||||||
|
};
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
let themeConfigOverrrides = new Map();
|
||||||
|
themeConfigOverrrides.set('agnoster.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('agnosterplus.omp.json', newThemeConfig(80));
|
||||||
|
themeConfigOverrrides.set('avit.omp.json', newThemeConfig(40, 80));
|
||||||
|
themeConfigOverrrides.set('blueish.omp.json', newThemeConfig(40, 100));
|
||||||
|
themeConfigOverrrides.set('cert.omp.json', newThemeConfig(40, 50));
|
||||||
|
themeConfigOverrrides.set('cinnamon.omp.json', newThemeConfig(40, 80));
|
||||||
|
themeConfigOverrrides.set('darkblood.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('honukai.omp.json', newThemeConfig(20));
|
||||||
|
themeConfigOverrrides.set('hotstick.minimal.omp.json', newThemeConfig(40, 10));
|
||||||
|
themeConfigOverrrides.set('huvix.omp.json', newThemeConfig(40, 70));
|
||||||
|
themeConfigOverrrides.set('jandedobbeleer.omp.json', newThemeConfig(40, 15));
|
||||||
|
themeConfigOverrrides.set('lambda.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('material.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('microverse-power.omp.json', newThemeConfig(40, 100));
|
||||||
|
themeConfigOverrrides.set('negligible.omp.json', newThemeConfig(10));
|
||||||
|
themeConfigOverrrides.set('paradox.omp.json', newThemeConfig(40, 100));
|
||||||
|
themeConfigOverrrides.set('powerlevel10k_classic.omp.json', newThemeConfig(10));
|
||||||
|
themeConfigOverrrides.set('powerlevel10k_lean.omp.json', newThemeConfig(80));
|
||||||
|
themeConfigOverrrides.set('powerline.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('pure.omp.json', newThemeConfig(40, 80));
|
||||||
|
themeConfigOverrrides.set('remk.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('robbyrussel.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('slim.omp.json', newThemeConfig(10, 80));
|
||||||
|
themeConfigOverrrides.set('slimfat.omp.json', newThemeConfig(10, 93));
|
||||||
|
themeConfigOverrrides.set('space.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('spaceship.omp.json', newThemeConfig(40, 40));
|
||||||
|
themeConfigOverrrides.set('star.omp.json', newThemeConfig(40, 70));
|
||||||
|
themeConfigOverrrides.set('stelbent.minimal.omp.json', newThemeConfig(70));
|
||||||
|
themeConfigOverrrides.set('ys.omp.json', newThemeConfig(40, 100));
|
||||||
|
themeConfigOverrrides.set('zash.omp.json', newThemeConfig(40, 40));
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const themes = await fs.promises.readdir(themesConfigDir);
|
||||||
|
let links = new Array();
|
||||||
|
|
||||||
|
for (const theme of themes) {
|
||||||
|
if (!theme.endsWith('.omp.json')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const configPath = path.join(themesConfigDir, theme);
|
||||||
|
|
||||||
|
let config = newThemeConfig();
|
||||||
|
if (themeConfigOverrrides.has(theme)) {
|
||||||
|
config = themeConfigOverrrides.get(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
let poshCommand = `oh-my-posh --config=${configPath} --shell shell --export-png`;
|
||||||
|
poshCommand += ` --rprompt-offset=${config.rpromptOffset}`;
|
||||||
|
poshCommand += ` --cursor-padding=${config.cursorPadding}`;
|
||||||
|
if (config.author !== '') {
|
||||||
|
poshCommand += ` --author=${config.author}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { _, stderr } = await exec(poshCommand);
|
||||||
|
|
||||||
|
if (stderr !== '') {
|
||||||
|
console.error(`Unable to create image for ${theme}, please try manually`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const image = theme.replace('.omp.json', '.png');
|
||||||
|
const toPath = path.join(themesStaticDir, image);
|
||||||
|
|
||||||
|
await fs.promises.rename(image, toPath);
|
||||||
|
|
||||||
|
const themeName = theme.replace('.omp.json', '');
|
||||||
|
|
||||||
|
const themeData = `
|
||||||
|
### [${themeName}]
|
||||||
|
|
||||||
|
[![${themeName}](/img/themes/${themeName}.png)][${themeName}]
|
||||||
|
`;
|
||||||
|
|
||||||
|
await fs.promises.appendFile('./docs/themes.md', themeData);
|
||||||
|
|
||||||
|
links.push(`[${themeName}]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/themes/${theme} '${themeName}'\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const link of links) {
|
||||||
|
await fs.promises.appendFile('./docs/themes.md', link);
|
||||||
|
}
|
||||||
|
})();
|
|
@ -5,7 +5,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "docusaurus start",
|
"start": "docusaurus start",
|
||||||
"build": "docusaurus build",
|
"build": "docusaurus build",
|
||||||
"swizzle": "docusaurus swizzle"
|
"themes": "node export_themes.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "2.0.0-alpha.72",
|
"@docusaurus/core": "2.0.0-alpha.72",
|
||||||
|
|
|
@ -3,7 +3,7 @@ module.exports = {
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
label: "Getting Started",
|
label: "Getting Started",
|
||||||
items: ["introduction", "upgrading", "installation", "configure", "themes", "fonts"],
|
items: ["introduction", "upgrading", "installation", "configure", "themes", "share", "fonts"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "category",
|
type: "category",
|
||||||
|
|
0
docs/static/img/themes/.keep
vendored
Normal file
BIN
docs/static/img/themes/agnoster.png
vendored
Before Width: | Height: | Size: 80 KiB |
BIN
docs/static/img/themes/agnosterplus.png
vendored
Before Width: | Height: | Size: 83 KiB |
BIN
docs/static/img/themes/aliens.png
vendored
Before Width: | Height: | Size: 79 KiB |
BIN
docs/static/img/themes/avit.png
vendored
Before Width: | Height: | Size: 67 KiB |
BIN
docs/static/img/themes/darkblood.png
vendored
Before Width: | Height: | Size: 71 KiB |
BIN
docs/static/img/themes/emodipt.png
vendored
Before Width: | Height: | Size: 94 KiB |
BIN
docs/static/img/themes/fish.png
vendored
Before Width: | Height: | Size: 77 KiB |
BIN
docs/static/img/themes/honukai.png
vendored
Before Width: | Height: | Size: 83 KiB |
BIN
docs/static/img/themes/jandedobbeleer.png
vendored
Before Width: | Height: | Size: 94 KiB |
BIN
docs/static/img/themes/lambda.png
vendored
Before Width: | Height: | Size: 66 KiB |
BIN
docs/static/img/themes/material.png
vendored
Before Width: | Height: | Size: 69 KiB |
BIN
docs/static/img/themes/paradox.png
vendored
Before Width: | Height: | Size: 82 KiB |
BIN
docs/static/img/themes/pararussel.png
vendored
Before Width: | Height: | Size: 73 KiB |
BIN
docs/static/img/themes/powerlevel10k_classic.png
vendored
Before Width: | Height: | Size: 86 KiB |
BIN
docs/static/img/themes/powerlevel10k_lean.png
vendored
Before Width: | Height: | Size: 70 KiB |
BIN
docs/static/img/themes/powerline.png
vendored
Before Width: | Height: | Size: 78 KiB |
BIN
docs/static/img/themes/robbyrussel.png
vendored
Before Width: | Height: | Size: 65 KiB |
BIN
docs/static/img/themes/sorin.png
vendored
Before Width: | Height: | Size: 79 KiB |
BIN
docs/static/img/themes/star.png
vendored
Before Width: | Height: | Size: 67 KiB |
BIN
docs/static/img/themes/zash.png
vendored
Before Width: | Height: | Size: 67 KiB |
|
@ -3,8 +3,10 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
"golang.org/x/text/unicode/norm"
|
const (
|
||||||
|
ANSIRegex = "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ansiFormats struct {
|
type ansiFormats struct {
|
||||||
|
@ -44,7 +46,7 @@ func (a *ansiFormats) init(shell string) {
|
||||||
a.title = "%%{\x1b]0;%s\007%%}"
|
a.title = "%%{\x1b]0;%s\007%%}"
|
||||||
a.colorSingle = "%%{\x1b[%sm%%}%s%%{\x1b[0m%%}"
|
a.colorSingle = "%%{\x1b[%sm%%}%s%%{\x1b[0m%%}"
|
||||||
a.colorFull = "%%{\x1b[%sm\x1b[%sm%%}%s%%{\x1b[0m%%}"
|
a.colorFull = "%%{\x1b[%sm\x1b[%sm%%}%s%%{\x1b[0m%%}"
|
||||||
a.colorTransparent = "%%{\x1b[%s;49m\x1b[7m%%}%s%%{\x1b[m\x1b[0m%%}"
|
a.colorTransparent = "%%{\x1b[%s;49m\x1b[7m%%}%s%%{\x1b[0m%%}"
|
||||||
a.escapeLeft = "%{"
|
a.escapeLeft = "%{"
|
||||||
a.escapeRight = "%}"
|
a.escapeRight = "%}"
|
||||||
a.hyperlink = "%%{\x1b]8;;%s\x1b\\%%}%s%%{\x1b]8;;\x1b\\%%}"
|
a.hyperlink = "%%{\x1b]8;;%s\x1b\\%%}%s%%{\x1b]8;;\x1b\\%%}"
|
||||||
|
@ -64,7 +66,7 @@ func (a *ansiFormats) init(shell string) {
|
||||||
a.title = "\\[\x1b]0;%s\007\\]"
|
a.title = "\\[\x1b]0;%s\007\\]"
|
||||||
a.colorSingle = "\\[\x1b[%sm\\]%s\\[\x1b[0m\\]"
|
a.colorSingle = "\\[\x1b[%sm\\]%s\\[\x1b[0m\\]"
|
||||||
a.colorFull = "\\[\x1b[%sm\x1b[%sm\\]%s\\[\x1b[0m\\]"
|
a.colorFull = "\\[\x1b[%sm\x1b[%sm\\]%s\\[\x1b[0m\\]"
|
||||||
a.colorTransparent = "\\[\x1b[%s;49m\x1b[7m\\]%s\\[\x1b[m\x1b[0m\\]"
|
a.colorTransparent = "\\[\x1b[%s;49m\x1b[7m\\]%s\\[\x1b[0m\\]"
|
||||||
a.escapeLeft = "\\["
|
a.escapeLeft = "\\["
|
||||||
a.escapeRight = "\\]"
|
a.escapeRight = "\\]"
|
||||||
a.hyperlink = "\\[\x1b]8;;%s\x1b\\\\\\]%s\\[\x1b]8;;\x1b\\\\\\]"
|
a.hyperlink = "\\[\x1b]8;;%s\x1b\\\\\\]%s\\[\x1b]8;;\x1b\\\\\\]"
|
||||||
|
@ -84,7 +86,7 @@ func (a *ansiFormats) init(shell string) {
|
||||||
a.title = "\x1b]0;%s\007"
|
a.title = "\x1b]0;%s\007"
|
||||||
a.colorSingle = "\x1b[%sm%s\x1b[0m"
|
a.colorSingle = "\x1b[%sm%s\x1b[0m"
|
||||||
a.colorFull = "\x1b[%sm\x1b[%sm%s\x1b[0m"
|
a.colorFull = "\x1b[%sm\x1b[%sm%s\x1b[0m"
|
||||||
a.colorTransparent = "\x1b[%s;49m\x1b[7m%s\x1b[m\x1b[0m"
|
a.colorTransparent = "\x1b[%s;49m\x1b[7m%s\x1b[0m"
|
||||||
a.escapeLeft = ""
|
a.escapeLeft = ""
|
||||||
a.escapeRight = ""
|
a.escapeRight = ""
|
||||||
a.hyperlink = "\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\"
|
a.hyperlink = "\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\"
|
||||||
|
@ -93,23 +95,28 @@ func (a *ansiFormats) init(shell string) {
|
||||||
a.italic = "\x1b[3m%s\x1b[23m"
|
a.italic = "\x1b[3m%s\x1b[23m"
|
||||||
a.underline = "\x1b[4m%s\x1b[24m"
|
a.underline = "\x1b[4m%s\x1b[24m"
|
||||||
a.strikethrough = "\x1b[9m%s\x1b[29m"
|
a.strikethrough = "\x1b[9m%s\x1b[29m"
|
||||||
a.strikethrough = "\x1b[9m%s\x1b[29m"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ansiFormats) lenWithoutANSI(text string) int {
|
func (a *ansiFormats) lenWithoutANSI(text string) int {
|
||||||
rANSI := "[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"
|
if len(text) == 0 {
|
||||||
stripped := replaceAllString(rANSI, text, "")
|
return 0
|
||||||
|
}
|
||||||
|
// replace hyperlinks
|
||||||
|
matches := findAllNamedRegexMatch(`(?P<STR>\x1b]8;;file:\/\/(.+)\x1b\\(?P<URL>.+)\x1b]8;;\x1b\\)`, text)
|
||||||
|
for _, match := range matches {
|
||||||
|
text = strings.ReplaceAll(text, match[STR], match[URL])
|
||||||
|
}
|
||||||
|
// replace console title
|
||||||
|
matches = findAllNamedRegexMatch(`(?P<STR>\x1b\]0;(.+)\007)`, text)
|
||||||
|
for _, match := range matches {
|
||||||
|
text = strings.ReplaceAll(text, match[STR], "")
|
||||||
|
}
|
||||||
|
stripped := replaceAllString(ANSIRegex, text, "")
|
||||||
stripped = strings.ReplaceAll(stripped, a.escapeLeft, "")
|
stripped = strings.ReplaceAll(stripped, a.escapeLeft, "")
|
||||||
stripped = strings.ReplaceAll(stripped, a.escapeRight, "")
|
stripped = strings.ReplaceAll(stripped, a.escapeRight, "")
|
||||||
var i norm.Iter
|
runeText := []rune(stripped)
|
||||||
i.InitString(norm.NFD, stripped)
|
return len(runeText)
|
||||||
var count int
|
|
||||||
for !i.Done() {
|
|
||||||
i.Next()
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *ansiFormats) generateHyperlink(text string) string {
|
func (a *ansiFormats) generateHyperlink(text string) string {
|
||||||
|
|
|
@ -129,7 +129,7 @@ func (e *engine) setStringValues(segments []*Segment) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) render() {
|
func (e *engine) render() string {
|
||||||
for _, block := range e.config.Blocks {
|
for _, block := range e.config.Blocks {
|
||||||
// if line break, append a line break
|
// if line break, append a line break
|
||||||
switch block.Type {
|
switch block.Type {
|
||||||
|
@ -161,19 +161,18 @@ func (e *engine) render() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !e.config.OSC99 {
|
if !e.config.OSC99 {
|
||||||
e.print()
|
return e.print()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
cwd := e.env.getcwd()
|
cwd := e.env.getcwd()
|
||||||
if e.env.isWsl() {
|
if e.env.isWsl() {
|
||||||
cwd, _ = e.env.runCommand("wslpath", "-m", cwd)
|
cwd, _ = e.env.runCommand("wslpath", "-m", cwd)
|
||||||
}
|
}
|
||||||
e.renderer.osc99(cwd)
|
e.renderer.osc99(cwd)
|
||||||
e.print()
|
return e.print()
|
||||||
}
|
}
|
||||||
|
|
||||||
// debug will loop through your config file and output the timings for each segments
|
// debug will loop through your config file and output the timings for each segments
|
||||||
func (e *engine) debug() {
|
func (e *engine) debug() string {
|
||||||
var segmentTimings []SegmentTiming
|
var segmentTimings []SegmentTiming
|
||||||
largestSegmentNameLength := 0
|
largestSegmentNameLength := 0
|
||||||
e.renderer.write("\n\x1b[1mHere are the timings of segments in your prompt:\x1b[0m\n\n")
|
e.renderer.write("\n\x1b[1mHere are the timings of segments in your prompt:\x1b[0m\n\n")
|
||||||
|
@ -236,19 +235,19 @@ func (e *engine) debug() {
|
||||||
segmentName := fmt.Sprintf("%s(%t)", segment.name, segment.enabled)
|
segmentName := fmt.Sprintf("%s(%t)", segment.name, segment.enabled)
|
||||||
e.renderer.write(fmt.Sprintf("%-*s - %3d ms - %s\n", largestSegmentNameLength, segmentName, duration, segment.stringValue))
|
e.renderer.write(fmt.Sprintf("%-*s - %3d ms - %s\n", largestSegmentNameLength, segmentName, duration, segment.stringValue))
|
||||||
}
|
}
|
||||||
fmt.Print(e.renderer.string())
|
return e.renderer.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) print() {
|
func (e *engine) print() string {
|
||||||
switch e.env.getShellName() {
|
switch e.env.getShellName() {
|
||||||
case zsh:
|
case zsh:
|
||||||
if *e.env.getArgs().Eval {
|
if *e.env.getArgs().Eval {
|
||||||
// escape double quotes contained in the prompt
|
// escape double quotes contained in the prompt
|
||||||
fmt.Printf("PS1=\"%s\"", strings.ReplaceAll(e.renderer.string(), "\"", "\"\""))
|
prompt := fmt.Sprintf("PS1=\"%s\"", strings.ReplaceAll(e.renderer.string(), "\"", "\"\""))
|
||||||
fmt.Printf("\nRPROMPT=\"%s\"", e.rprompt)
|
prompt += fmt.Sprintf("\nRPROMPT=\"%s\"", e.rprompt)
|
||||||
return
|
return prompt
|
||||||
}
|
}
|
||||||
case pwsh, powershell5, bash:
|
case pwsh, powershell5, bash, shelly:
|
||||||
if e.rprompt != "" {
|
if e.rprompt != "" {
|
||||||
e.renderer.saveCursorPosition()
|
e.renderer.saveCursorPosition()
|
||||||
e.renderer.carriageForward()
|
e.renderer.carriageForward()
|
||||||
|
@ -257,7 +256,7 @@ func (e *engine) print() {
|
||||||
e.renderer.restoreCursorPosition()
|
e.renderer.restoreCursorPosition()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt.Print(e.renderer.string())
|
return e.renderer.string()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *engine) resetBlock() {
|
func (e *engine) resetBlock() {
|
||||||
|
|
BIN
src/font/VictorMono-Bold.ttf
Normal file
BIN
src/font/VictorMono-Italic.ttf
Normal file
BIN
src/font/VictorMono-Regular.ttf
Normal file
|
@ -11,7 +11,10 @@ require (
|
||||||
github.com/alecthomas/colour v0.1.0 // indirect
|
github.com/alecthomas/colour v0.1.0 // indirect
|
||||||
github.com/alecthomas/repr v0.0.0-20210301060118-828286944d6a // indirect
|
github.com/alecthomas/repr v0.0.0-20210301060118-828286944d6a // indirect
|
||||||
github.com/distatus/battery v0.10.0
|
github.com/distatus/battery v0.10.0
|
||||||
|
github.com/esimov/stackblur-go v1.0.0
|
||||||
|
github.com/fogleman/gg v1.3.0
|
||||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
github.com/google/uuid v1.2.0 // indirect
|
github.com/google/uuid v1.2.0 // indirect
|
||||||
github.com/gookit/color v1.3.8
|
github.com/gookit/color v1.3.8
|
||||||
github.com/gookit/config/v2 v2.0.22
|
github.com/gookit/config/v2 v2.0.22
|
||||||
|
@ -24,6 +27,7 @@ require (
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 // indirect
|
||||||
|
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
|
||||||
golang.org/x/sys v0.0.0-20210324051608-47abb6519492
|
golang.org/x/sys v0.0.0-20210324051608-47abb6519492
|
||||||
golang.org/x/text v0.3.5
|
golang.org/x/text v0.3.5
|
||||||
howett.net/plist v0.0.0-20201203080718-1454fab16a06 // indirect
|
howett.net/plist v0.0.0-20201203080718-1454fab16a06 // indirect
|
||||||
|
|
|
@ -23,9 +23,15 @@ github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJE
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/esimov/stackblur-go v1.0.0 h1:PuXWrQ16VIh6Di+tn3CpKAyzkIIECo9DPGVecrzyDGc=
|
||||||
|
github.com/esimov/stackblur-go v1.0.0/go.mod h1:a3zzeKuJKUpCcReHmEsuPaEnq42D2b/bHoCI8UjIuMY=
|
||||||
|
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||||
|
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
|
github.com/go-ole/go-ole v1.2.5 h1:t4MGB5xEDZvXI+0rMjjsfBsD7yAgp/s9ZDkL1JndXwY=
|
||||||
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
@ -101,6 +107,8 @@ golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
|
||||||
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
|
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb h1:fqpd0EBDzlHRCjiphRR5Zo/RSWWQlWv34418dnEixWk=
|
||||||
|
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
|
444
src/image.go
Normal file
|
@ -0,0 +1,444 @@
|
||||||
|
// Copyright © 2020 The Homeport Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
// THE SOFTWARE.
|
||||||
|
|
||||||
|
// https://github.com/homeport/termshot
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/esimov/stackblur-go"
|
||||||
|
"github.com/fogleman/gg"
|
||||||
|
"github.com/golang/freetype/truetype"
|
||||||
|
"golang.org/x/image/font"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
red = "#ED655A"
|
||||||
|
yellow = "#E1C04C"
|
||||||
|
green = "#71BD47"
|
||||||
|
|
||||||
|
// known ansi sequences
|
||||||
|
FG = "FG"
|
||||||
|
BG = "BG"
|
||||||
|
STR = "STR"
|
||||||
|
URL = "URL"
|
||||||
|
invertedColor = "inverted"
|
||||||
|
invertedColorSingle = "invertedsingle"
|
||||||
|
fullColor = "full"
|
||||||
|
foreground = "foreground"
|
||||||
|
reset = "reset"
|
||||||
|
bold = "bold"
|
||||||
|
boldReset = "boldr"
|
||||||
|
italic = "italic"
|
||||||
|
italicReset = "italicr"
|
||||||
|
underline = "underline"
|
||||||
|
underlineReset = "underliner"
|
||||||
|
strikethrough = "strikethrough"
|
||||||
|
strikethroughReset = "strikethroughr"
|
||||||
|
color16 = "color16"
|
||||||
|
left = "left"
|
||||||
|
osc99 = "osc99"
|
||||||
|
lineChange = "linechange"
|
||||||
|
title = "title"
|
||||||
|
link = "link"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed font/VictorMono-Bold.ttf
|
||||||
|
var victorMonoBold []byte
|
||||||
|
|
||||||
|
//go:embed font/VictorMono-Regular.ttf
|
||||||
|
var victorMonoRegular []byte
|
||||||
|
|
||||||
|
//go:embed font/VictorMono-Italic.ttf
|
||||||
|
var victorMonoItalic []byte
|
||||||
|
|
||||||
|
type RGB struct {
|
||||||
|
r int
|
||||||
|
g int
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRGBColor(ansiColor string) *RGB {
|
||||||
|
colors := strings.Split(ansiColor, ";")
|
||||||
|
r, _ := strconv.Atoi(colors[0])
|
||||||
|
g, _ := strconv.Atoi(colors[1])
|
||||||
|
b, _ := strconv.Atoi(colors[2])
|
||||||
|
return &RGB{
|
||||||
|
r: r,
|
||||||
|
g: g,
|
||||||
|
b: b,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImageRenderer struct {
|
||||||
|
ansiString string
|
||||||
|
author string
|
||||||
|
formats *ansiFormats
|
||||||
|
|
||||||
|
factor float64
|
||||||
|
|
||||||
|
columns int
|
||||||
|
rows int
|
||||||
|
|
||||||
|
defaultForegroundColor *RGB
|
||||||
|
defaultBackgroundColor *RGB
|
||||||
|
|
||||||
|
shadowBaseColor string
|
||||||
|
shadowRadius uint8
|
||||||
|
shadowOffsetX float64
|
||||||
|
shadowOffsetY float64
|
||||||
|
|
||||||
|
padding float64
|
||||||
|
margin float64
|
||||||
|
|
||||||
|
regular font.Face
|
||||||
|
bold font.Face
|
||||||
|
italic font.Face
|
||||||
|
lineSpacing float64
|
||||||
|
|
||||||
|
// canvas switches
|
||||||
|
style string
|
||||||
|
backgroundColor *RGB
|
||||||
|
foregroundColor *RGB
|
||||||
|
ansiSequenceRegexMap map[string]string
|
||||||
|
rPromptOffset int
|
||||||
|
cursorPadding int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ir *ImageRenderer) init() {
|
||||||
|
f := 2.0
|
||||||
|
|
||||||
|
ir.cleanContent()
|
||||||
|
|
||||||
|
fontRegular, _ := truetype.Parse(victorMonoRegular)
|
||||||
|
fontBold, _ := truetype.Parse(victorMonoBold)
|
||||||
|
fontItalic, _ := truetype.Parse(victorMonoItalic)
|
||||||
|
fontFaceOptions := &truetype.Options{Size: f * 12, DPI: 144}
|
||||||
|
|
||||||
|
ir.defaultForegroundColor = &RGB{255, 255, 255}
|
||||||
|
ir.defaultBackgroundColor = &RGB{21, 21, 21}
|
||||||
|
|
||||||
|
ir.factor = f
|
||||||
|
|
||||||
|
ir.columns = 80
|
||||||
|
ir.rows = 25
|
||||||
|
|
||||||
|
ir.margin = f * 48
|
||||||
|
ir.padding = f * 24
|
||||||
|
|
||||||
|
ir.shadowBaseColor = "#10101066"
|
||||||
|
ir.shadowRadius = uint8(math.Min(f*16, 255))
|
||||||
|
ir.shadowOffsetX = f * 16
|
||||||
|
ir.shadowOffsetY = f * 16
|
||||||
|
|
||||||
|
ir.regular = truetype.NewFace(fontRegular, fontFaceOptions)
|
||||||
|
ir.bold = truetype.NewFace(fontBold, fontFaceOptions)
|
||||||
|
ir.italic = truetype.NewFace(fontItalic, fontFaceOptions)
|
||||||
|
ir.lineSpacing = 1.2
|
||||||
|
|
||||||
|
ir.ansiSequenceRegexMap = map[string]string{
|
||||||
|
invertedColor: `^(?P<STR>(\x1b\[38;2;(?P<BG>(\d+;?){3});49m){1}(\x1b\[7m))`,
|
||||||
|
invertedColorSingle: `^(?P<STR>\x1b\[(?P<BG>\d{2,3});49m\x1b\[7m)`,
|
||||||
|
fullColor: `^(?P<STR>(\x1b\[48;2;(?P<BG>(\d+;?){3})m)(\x1b\[38;2;(?P<FG>(\d+;?){3})m))`,
|
||||||
|
foreground: `^(?P<STR>(\x1b\[38;2;(?P<FG>(\d+;?){3})m))`,
|
||||||
|
reset: `^(?P<STR>\x1b\[0m)`,
|
||||||
|
bold: `^(?P<STR>\x1b\[1m)`,
|
||||||
|
boldReset: `^(?P<STR>\x1b\[22m)`,
|
||||||
|
italic: `^(?P<STR>\x1b\[3m)`,
|
||||||
|
italicReset: `^(?P<STR>\x1b\[23m)`,
|
||||||
|
underline: `^(?P<STR>\x1b\[4m)`,
|
||||||
|
underlineReset: `^(?P<STR>\x1b\[24m)`,
|
||||||
|
strikethrough: `^(?P<STR>\x1b\[9m)`,
|
||||||
|
strikethroughReset: `^(?P<STR>\x1b\[29m)`,
|
||||||
|
color16: `^(?P<STR>\x1b\[(?P<FG>\d{2,3})m)`,
|
||||||
|
left: `^(?P<STR>\x1b\[(\d{1,3})D)`,
|
||||||
|
osc99: `^(?P<STR>\x1b\]9;9;(.+)\x1b\\)`,
|
||||||
|
lineChange: `^(?P<STR>\x1b\[(\d)[FB])`,
|
||||||
|
title: `^(?P<STR>\x1b\]0;(.+)\007)`,
|
||||||
|
link: `^(?P<STR>\x1b]8;;file:\/\/(.+)\x1b\\(?P<URL>.+)\x1b]8;;\x1b\\)`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ir *ImageRenderer) fontHeight() float64 {
|
||||||
|
return float64(ir.regular.Metrics().Height >> 6)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ir *ImageRenderer) calculateWidth() int {
|
||||||
|
longest := 0
|
||||||
|
for _, line := range strings.Split(ir.ansiString, "\n") {
|
||||||
|
length := ir.formats.lenWithoutANSI(line)
|
||||||
|
if length > longest {
|
||||||
|
longest = length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return longest
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ir *ImageRenderer) cleanContent() {
|
||||||
|
rPromptAnsi := "\x1b7\x1b[1000C"
|
||||||
|
hasRPrompt := strings.Contains(ir.ansiString, rPromptAnsi)
|
||||||
|
// clean abundance of empty lines
|
||||||
|
ir.ansiString = strings.Trim(ir.ansiString, "\n")
|
||||||
|
ir.ansiString = "\n" + ir.ansiString
|
||||||
|
// clean string before render
|
||||||
|
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b[m", "\x1b[0m")
|
||||||
|
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b[K", "")
|
||||||
|
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b[1F", "")
|
||||||
|
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b8", "")
|
||||||
|
// replace rprompt with adding and mark right aligned blocks with a pointer
|
||||||
|
ir.ansiString = strings.ReplaceAll(ir.ansiString, rPromptAnsi, fmt.Sprintf("_%s", strings.Repeat(" ", ir.cursorPadding)))
|
||||||
|
ir.ansiString = strings.ReplaceAll(ir.ansiString, "\x1b[1000C", strings.Repeat(" ", ir.rPromptOffset))
|
||||||
|
if !hasRPrompt {
|
||||||
|
ir.ansiString += fmt.Sprintf("_%s", strings.Repeat(" ", ir.cursorPadding))
|
||||||
|
}
|
||||||
|
// add watermarks
|
||||||
|
ir.ansiString += "\n\n\x1b[1mhttps://ohmyposh.dev\x1b[22m"
|
||||||
|
if len(ir.author) > 0 {
|
||||||
|
createdBy := fmt.Sprintf(" by \x1b[1m%s\x1b[22m", ir.author)
|
||||||
|
ir.ansiString += createdBy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ir *ImageRenderer) measureContent() (width, height float64) {
|
||||||
|
// get the longest line
|
||||||
|
linewidth := ir.calculateWidth()
|
||||||
|
// width, taken from the longest line
|
||||||
|
tmpDrawer := &font.Drawer{Face: ir.regular}
|
||||||
|
advance := tmpDrawer.MeasureString(strings.Repeat(" ", linewidth))
|
||||||
|
width = float64(advance >> 6)
|
||||||
|
// height, lines times font height and line spacing
|
||||||
|
height = float64(len(strings.Split(ir.ansiString, "\n"))) * ir.fontHeight() * ir.lineSpacing
|
||||||
|
return width, height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ir *ImageRenderer) SavePNG(path string) error {
|
||||||
|
var f = func(value float64) float64 { return ir.factor * value }
|
||||||
|
|
||||||
|
var (
|
||||||
|
corner = f(6)
|
||||||
|
radius = f(9)
|
||||||
|
distance = f(25)
|
||||||
|
)
|
||||||
|
|
||||||
|
contentWidth, contentHeight := ir.measureContent()
|
||||||
|
|
||||||
|
// Make sure the output window is big enough in case no content or very few
|
||||||
|
// content will be rendered
|
||||||
|
contentWidth = math.Max(contentWidth, 3*distance+3*radius)
|
||||||
|
|
||||||
|
marginX, marginY := ir.margin, ir.margin
|
||||||
|
paddingX, paddingY := ir.padding, ir.padding
|
||||||
|
|
||||||
|
xOffset := marginX
|
||||||
|
yOffset := marginY
|
||||||
|
titleOffset := f(40)
|
||||||
|
|
||||||
|
width := contentWidth + 2*marginX + 2*paddingX
|
||||||
|
height := contentHeight + 2*marginY + 2*paddingY + titleOffset
|
||||||
|
|
||||||
|
dc := gg.NewContext(int(width), int(height))
|
||||||
|
|
||||||
|
xOffset -= ir.shadowOffsetX / 2
|
||||||
|
yOffset -= ir.shadowOffsetY / 2
|
||||||
|
|
||||||
|
bc := gg.NewContext(int(width), int(height))
|
||||||
|
bc.DrawRoundedRectangle(xOffset+ir.shadowOffsetX, yOffset+ir.shadowOffsetY, width-2*marginX, height-2*marginY, corner)
|
||||||
|
bc.SetHexColor(ir.shadowBaseColor)
|
||||||
|
bc.Fill()
|
||||||
|
|
||||||
|
var done = make(chan struct{}, ir.shadowRadius)
|
||||||
|
shadow := stackblur.Process(
|
||||||
|
bc.Image(),
|
||||||
|
uint32(width),
|
||||||
|
uint32(height),
|
||||||
|
uint32(ir.shadowRadius),
|
||||||
|
done,
|
||||||
|
)
|
||||||
|
|
||||||
|
<-done
|
||||||
|
dc.DrawImage(shadow, 0, 0)
|
||||||
|
|
||||||
|
// Draw rounded rectangle with outline and three button to produce the
|
||||||
|
// impression of a window with controls and a content area
|
||||||
|
dc.DrawRoundedRectangle(xOffset, yOffset, width-2*marginX, height-2*marginY, corner)
|
||||||
|
dc.SetHexColor("#151515")
|
||||||
|
dc.Fill()
|
||||||
|
|
||||||
|
dc.DrawRoundedRectangle(xOffset, yOffset, width-2*marginX, height-2*marginY, corner)
|
||||||
|
dc.SetHexColor("#404040")
|
||||||
|
dc.SetLineWidth(f(1))
|
||||||
|
dc.Stroke()
|
||||||
|
|
||||||
|
for i, color := range []string{red, yellow, green} {
|
||||||
|
dc.DrawCircle(xOffset+paddingX+float64(i)*distance+f(4), yOffset+paddingY+f(4), radius)
|
||||||
|
dc.SetHexColor(color)
|
||||||
|
dc.Fill()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the actual text into the prepared content area of the window
|
||||||
|
var x, y float64 = xOffset + paddingX, yOffset + paddingY + titleOffset + ir.fontHeight()
|
||||||
|
|
||||||
|
for len(ir.ansiString) != 0 {
|
||||||
|
if !ir.shouldPrint() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
runes := []rune(ir.ansiString)
|
||||||
|
str := string(runes[0:1])
|
||||||
|
ir.ansiString = string(runes[1:])
|
||||||
|
switch ir.style {
|
||||||
|
case bold:
|
||||||
|
dc.SetFontFace(ir.bold)
|
||||||
|
case italic:
|
||||||
|
dc.SetFontFace(ir.italic)
|
||||||
|
default:
|
||||||
|
dc.SetFontFace(ir.regular)
|
||||||
|
}
|
||||||
|
|
||||||
|
w, h := dc.MeasureString(str)
|
||||||
|
if ir.backgroundColor != nil {
|
||||||
|
dc.SetRGB255(ir.backgroundColor.r, ir.backgroundColor.g, ir.backgroundColor.b)
|
||||||
|
dc.DrawRectangle(x, y-h, w, h+12)
|
||||||
|
dc.Fill()
|
||||||
|
}
|
||||||
|
if ir.foregroundColor != nil {
|
||||||
|
dc.SetRGB255(ir.foregroundColor.r, ir.foregroundColor.g, ir.foregroundColor.b)
|
||||||
|
} else {
|
||||||
|
dc.SetRGB255(ir.defaultForegroundColor.r, ir.defaultForegroundColor.g, ir.defaultForegroundColor.b)
|
||||||
|
}
|
||||||
|
|
||||||
|
if str == "\n" {
|
||||||
|
x = xOffset + paddingX
|
||||||
|
y += h * ir.lineSpacing
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dc.DrawString(str, x, y)
|
||||||
|
|
||||||
|
if ir.style == underline {
|
||||||
|
dc.DrawLine(x, y+f(4), x+w, y+f(4))
|
||||||
|
dc.SetLineWidth(f(1))
|
||||||
|
dc.Stroke()
|
||||||
|
}
|
||||||
|
|
||||||
|
x += w
|
||||||
|
}
|
||||||
|
|
||||||
|
return dc.SavePNG(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ir *ImageRenderer) shouldPrint() bool {
|
||||||
|
for sequence, regex := range ir.ansiSequenceRegexMap {
|
||||||
|
match := findNamedRegexMatch(regex, ir.ansiString)
|
||||||
|
if len(match) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ir.ansiString = strings.TrimPrefix(ir.ansiString, match[STR])
|
||||||
|
switch sequence {
|
||||||
|
case invertedColor:
|
||||||
|
ir.foregroundColor = ir.defaultBackgroundColor
|
||||||
|
ir.backgroundColor = NewRGBColor(match[BG])
|
||||||
|
return false
|
||||||
|
case invertedColorSingle:
|
||||||
|
ir.foregroundColor = ir.defaultBackgroundColor
|
||||||
|
color, _ := strconv.Atoi(match[BG])
|
||||||
|
color += 10
|
||||||
|
ir.setBase16Color(fmt.Sprint(color))
|
||||||
|
return false
|
||||||
|
case fullColor:
|
||||||
|
ir.foregroundColor = NewRGBColor(match[FG])
|
||||||
|
ir.backgroundColor = NewRGBColor(match[BG])
|
||||||
|
return false
|
||||||
|
case foreground:
|
||||||
|
ir.foregroundColor = NewRGBColor(match[FG])
|
||||||
|
return false
|
||||||
|
case reset:
|
||||||
|
ir.foregroundColor = ir.defaultForegroundColor
|
||||||
|
ir.backgroundColor = nil
|
||||||
|
return false
|
||||||
|
case bold, italic, underline:
|
||||||
|
ir.style = sequence
|
||||||
|
return false
|
||||||
|
case boldReset, italicReset, underlineReset:
|
||||||
|
ir.style = ""
|
||||||
|
return false
|
||||||
|
case strikethrough, strikethroughReset, left, osc99, lineChange, title:
|
||||||
|
return false
|
||||||
|
case color16:
|
||||||
|
ir.setBase16Color(match[FG])
|
||||||
|
return false
|
||||||
|
case link:
|
||||||
|
ir.ansiString = match[URL] + ir.ansiString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ir *ImageRenderer) setBase16Color(colorStr string) {
|
||||||
|
color := ir.defaultForegroundColor
|
||||||
|
colorInt, err := strconv.Atoi(colorStr)
|
||||||
|
if err != nil {
|
||||||
|
ir.foregroundColor = color
|
||||||
|
}
|
||||||
|
switch colorInt {
|
||||||
|
case 30, 40: // Black
|
||||||
|
color = &RGB{1, 1, 1}
|
||||||
|
case 31, 41: // Red
|
||||||
|
color = &RGB{222, 56, 43}
|
||||||
|
case 32, 42: // Green
|
||||||
|
color = &RGB{57, 181, 74}
|
||||||
|
case 33, 43: // Yellow
|
||||||
|
color = &RGB{255, 199, 6}
|
||||||
|
case 34, 44: // Blue
|
||||||
|
color = &RGB{0, 111, 184}
|
||||||
|
case 35, 45: // Magenta
|
||||||
|
color = &RGB{118, 38, 113}
|
||||||
|
case 36, 46: // Cyan
|
||||||
|
color = &RGB{44, 181, 233}
|
||||||
|
case 37, 47: // White
|
||||||
|
color = &RGB{204, 204, 204}
|
||||||
|
case 90, 100: // Bright Black (Gray)
|
||||||
|
color = &RGB{128, 128, 128}
|
||||||
|
case 91, 101: // Bright Red
|
||||||
|
color = &RGB{255, 0, 0}
|
||||||
|
case 92, 102: // Bright Green
|
||||||
|
color = &RGB{0, 255, 0}
|
||||||
|
case 93, 103: // Bright Yellow
|
||||||
|
color = &RGB{255, 255, 0}
|
||||||
|
case 94, 104: // Bright Blue
|
||||||
|
color = &RGB{0, 0, 255}
|
||||||
|
case 95, 105: // Bright Magenta
|
||||||
|
color = &RGB{255, 0, 255}
|
||||||
|
case 96, 106: // Bright Cyan
|
||||||
|
color = &RGB{101, 194, 205}
|
||||||
|
case 97, 107: // Bright White
|
||||||
|
color = &RGB{255, 255, 255}
|
||||||
|
}
|
||||||
|
if colorInt < 40 || (colorInt >= 90 && colorInt < 100) {
|
||||||
|
ir.foregroundColor = color
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ir.backgroundColor = color
|
||||||
|
}
|
40
src/image_test.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func runImageTest(content string) error {
|
||||||
|
poshImagePath := "ohmyposh.png"
|
||||||
|
file, err := ioutil.TempFile("", poshImagePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer os.Remove(file.Name())
|
||||||
|
formats := &ansiFormats{}
|
||||||
|
formats.init(shelly)
|
||||||
|
image := &ImageRenderer{
|
||||||
|
ansiString: content,
|
||||||
|
formats: formats,
|
||||||
|
}
|
||||||
|
image.init()
|
||||||
|
err = image.SavePNG(poshImagePath)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringImageFileWithText(t *testing.T) {
|
||||||
|
err := runImageTest("foobar")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStringImageFileWithANSI(t *testing.T) {
|
||||||
|
prompt := `[38;2;0;55;218;49m[7m[m[0m[48;2;0;55;218m[38;2;255;255;255m oh-my-posh
|
||||||
|
[0m[48;2;193;156;0m[38;2;0;55;218m[0m[48;2;193;156;0m[38;2;17;17;17m main ≡ ~4 -8 ?7 [0m[38;2;193;156;0m[0m
|
||||||
|
[37m [0m[0m`
|
||||||
|
err := runImageTest(prompt)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
|
@ -115,3 +115,28 @@ function global:Export-PoshTheme {
|
||||||
$configString = @(&$omp --config="$config" --config-format="$Format" --print-config 2>&1)
|
$configString = @(&$omp --config="$config" --config-format="$Format" --print-config 2>&1)
|
||||||
[IO.File]::WriteAllLines($FilePath, $configString)
|
[IO.File]::WriteAllLines($FilePath, $configString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function global:Export-PoshImage {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $false)]
|
||||||
|
[int]
|
||||||
|
$RPromptOffset = 40,
|
||||||
|
[Parameter(Mandatory = $false)]
|
||||||
|
[int]
|
||||||
|
$CursorPadding = 30,
|
||||||
|
[Parameter(Mandatory = $false)]
|
||||||
|
[string]
|
||||||
|
$Author
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($Author) {
|
||||||
|
$Author = "--author=$Author"
|
||||||
|
}
|
||||||
|
|
||||||
|
$omp = "::OMP::"
|
||||||
|
$config = $global:PoshSettings.Theme
|
||||||
|
$cleanPWD = $PWD.ProviderPath.TrimEnd("\")
|
||||||
|
$cleanPSWD = $PWD.ToString().TrimEnd("\")
|
||||||
|
$standardOut = @(&$omp --config="$config" --pwd="$cleanPWD" --pswd="$cleanPSWD" --export-png --rprompt-offset="$RPromptOffset" --cursor-padding="$CursorPadding" $Author 2>&1)
|
||||||
|
$standardOut -join "`n"
|
||||||
|
}
|
||||||
|
|
42
src/main.go
|
@ -33,6 +33,7 @@ const (
|
||||||
pwsh = "pwsh"
|
pwsh = "pwsh"
|
||||||
fish = "fish"
|
fish = "fish"
|
||||||
powershell5 = "powershell"
|
powershell5 = "powershell"
|
||||||
|
shelly = "shell"
|
||||||
)
|
)
|
||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
|
@ -51,6 +52,10 @@ type args struct {
|
||||||
Eval *bool
|
Eval *bool
|
||||||
Init *bool
|
Init *bool
|
||||||
PrintInit *bool
|
PrintInit *bool
|
||||||
|
ExportPNG *bool
|
||||||
|
Author *string
|
||||||
|
CursorPadding *int
|
||||||
|
RPromptOffset *int
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -115,6 +120,22 @@ func main() {
|
||||||
"print-init",
|
"print-init",
|
||||||
false,
|
false,
|
||||||
"Print the shell initialization script"),
|
"Print the shell initialization script"),
|
||||||
|
ExportPNG: flag.Bool(
|
||||||
|
"export-png",
|
||||||
|
false,
|
||||||
|
"Create an image based on the current configuration"),
|
||||||
|
Author: flag.String(
|
||||||
|
"author",
|
||||||
|
"",
|
||||||
|
"Add the author to the exported image using --export-img"),
|
||||||
|
CursorPadding: flag.Int(
|
||||||
|
"cursor-padding",
|
||||||
|
30,
|
||||||
|
"Pad the cursor with x when using --export-img"),
|
||||||
|
RPromptOffset: flag.Int(
|
||||||
|
"rprompt-offset",
|
||||||
|
40,
|
||||||
|
"Offset the right prompt with x when using --export-img"),
|
||||||
}
|
}
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
env := &environment{}
|
env := &environment{}
|
||||||
|
@ -170,10 +191,27 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *args.Debug {
|
if *args.Debug {
|
||||||
engine.debug()
|
fmt.Print(engine.debug())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
engine.render()
|
prompt := engine.render()
|
||||||
|
if !*args.ExportPNG {
|
||||||
|
fmt.Print(prompt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imageCreator := &ImageRenderer{
|
||||||
|
ansiString: prompt,
|
||||||
|
author: *args.Author,
|
||||||
|
cursorPadding: *args.CursorPadding,
|
||||||
|
rPromptOffset: *args.RPromptOffset,
|
||||||
|
formats: formats,
|
||||||
|
}
|
||||||
|
imageCreator.init()
|
||||||
|
match := findNamedRegexMatch(`.*(\/|\\)(?P<STR>.+).omp.(json|yaml|toml)`, *args.Config)
|
||||||
|
err := imageCreator.SavePNG(fmt.Sprintf("%s.png", match[STR]))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Print(err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initShell(shell, configFile string) string {
|
func initShell(shell, configFile string) string {
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
"user_info_separator": "",
|
"user_info_separator": "",
|
||||||
"display_host": false,
|
"display_host": false,
|
||||||
"prefix": "",
|
"prefix": "",
|
||||||
"postfix": ""
|
"postfix": " "
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -42,8 +42,8 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"branch_icon": "",
|
"branch_icon": "",
|
||||||
"display_status": false,
|
"display_status": false,
|
||||||
"prefix": "git(",
|
"prefix": " git(",
|
||||||
"postfix": ")"
|
"postfix": ") "
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -55,8 +55,8 @@
|
||||||
"background": "lightMagenta",
|
"background": "lightMagenta",
|
||||||
"properties": {
|
"properties": {
|
||||||
"time_format": "15:04",
|
"time_format": "15:04",
|
||||||
"prefix": "",
|
"prefix": " ",
|
||||||
"postfix": ""
|
"postfix": " "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,74 +1,63 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
|
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
|
||||||
"final_space":true,
|
"final_space": true,
|
||||||
"osc99":true,
|
"osc99": true,
|
||||||
"console_title":true,
|
"console_title": true,
|
||||||
"console_title_style":"template",
|
"console_title_style": "template",
|
||||||
"console_title_template":"{{.Folder}}{{if .Root}} :: root{{end}} :: {{.Shell}}",
|
"console_title_template": "{{.Folder}}{{if .Root}} :: root{{end}} :: {{.Shell}}",
|
||||||
"blocks":[
|
"blocks": [
|
||||||
{
|
{
|
||||||
"type":"prompt",
|
"type": "prompt",
|
||||||
"alignment":"left",
|
"alignment": "left",
|
||||||
"horizontal_offset":0,
|
"segments": [
|
||||||
"vertical_offset":1,
|
{
|
||||||
"segments":[
|
"type": "root",
|
||||||
{
|
"style": "plain",
|
||||||
"type": "root",
|
"foreground": "yellow",
|
||||||
"style": "plain",
|
"properties": {
|
||||||
"foreground": "yellow",
|
"root_icon": ""
|
||||||
"properties": {
|
}
|
||||||
"root_icon": ""
|
},
|
||||||
}
|
{
|
||||||
},
|
"type": "path",
|
||||||
{
|
"style": "diamond",
|
||||||
"type":"path",
|
"foreground": "black",
|
||||||
"style":"diamond",
|
"background": "lightBlue",
|
||||||
"powerline_symbol":"",
|
"leading_diamond": "",
|
||||||
"invert_powerline":false,
|
"trailing_diamond": "",
|
||||||
"foreground":"black",
|
"properties": {
|
||||||
"foreground_templates":null,
|
"style": "mixed"
|
||||||
"background":"lightBlue",
|
}
|
||||||
"background_templates":null,
|
},
|
||||||
"leading_diamond":"",
|
{
|
||||||
"trailing_diamond":"",
|
"type": "git",
|
||||||
"properties":{
|
"style": "powerline",
|
||||||
"style":"mixed"
|
"powerline_symbol": "",
|
||||||
}
|
"foreground": "black",
|
||||||
},
|
"background": "green",
|
||||||
{
|
"properties": {
|
||||||
"type":"git",
|
"display_status_detail": true,
|
||||||
"style":"powerline",
|
"branch_icon": " ",
|
||||||
"powerline_symbol":"",
|
"branch_identical_icon": "≡",
|
||||||
"invert_powerline":false,
|
"branch_ahead_icon": "↑",
|
||||||
"foreground":"black",
|
"branch_behind_icon": "↓",
|
||||||
"foreground_templates":null,
|
"branch_gone": "≢",
|
||||||
"background":"green",
|
"local_working_icon": "",
|
||||||
"background_templates":null,
|
"local_staged_icon": "",
|
||||||
"leading_diamond":"",
|
"stash_count_icon": "",
|
||||||
"trailing_diamond":"",
|
"commit_icon": "▷ ",
|
||||||
"properties":{
|
"tag_icon": "▶ ",
|
||||||
"display_status_detail": true,
|
"rebase_icon": "Ɫ ",
|
||||||
"branch_icon":" ",
|
"cherry_pick_icon": "✓ ",
|
||||||
"branch_identical_icon":"≡",
|
"merge_icon": "◴ ",
|
||||||
"branch_ahead_icon":"↑",
|
"no_commits_icon": "[no commits]",
|
||||||
"branch_behind_icon":"↓",
|
"status_separator_icon": " │",
|
||||||
"branch_gone":"≢",
|
"status_colors_enabled": true,
|
||||||
"local_working_icon":"",
|
"color_background": true,
|
||||||
"local_staged_icon":"",
|
"local_changes_color": "yellow"
|
||||||
"stash_count_icon":"",
|
}
|
||||||
"commit_icon": "▷ ",
|
}
|
||||||
"tag_icon": "▶ ",
|
]
|
||||||
"rebase_icon": "Ɫ ",
|
}
|
||||||
"cherry_pick_icon": "✓ ",
|
]
|
||||||
"merge_icon": "◴ ",
|
}
|
||||||
"no_commits_icon": "[no commits]",
|
|
||||||
"status_separator_icon": " │",
|
|
||||||
"status_colors_enabled": true,
|
|
||||||
"color_background": true,
|
|
||||||
"local_changes_color": "yellow"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
|
@ -32,6 +32,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"final_space": true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"foreground": "#ffffff",
|
"foreground": "#ffffff",
|
||||||
"properties": {
|
"properties": {
|
||||||
"prefix": "",
|
"prefix": "",
|
||||||
|
"postfix": "",
|
||||||
"text": "<#C591E8>\u276F</><#69FF94>\u276F</>"
|
"text": "<#C591E8>\u276F</><#69FF94>\u276F</>"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -52,6 +53,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"final_space": true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
{
|
{
|
||||||
"type": "os",
|
"type": "os",
|
||||||
"style": "plain",
|
"style": "plain",
|
||||||
"foreground": "#3A86FF"
|
"foreground": "#3A86FF",
|
||||||
|
"properties": {
|
||||||
|
"prefix": ""
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "session",
|
"type": "session",
|
||||||
|
@ -101,6 +104,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"final_space": true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
"style": "plain",
|
"style": "plain",
|
||||||
"foreground": "#56B6C2",
|
"foreground": "#56B6C2",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"prefix": "",
|
||||||
"style": "folder"
|
"style": "folder"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -77,6 +78,5 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"final_space": true
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +1,92 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
|
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
|
||||||
"console_title": true,
|
"console_title": true,
|
||||||
"console_title_style": "template",
|
"console_title_style": "template",
|
||||||
"console_title_template": "{{if .Root}}(Admin){{end}} {{.Path}}",
|
"console_title_template": "{{if .Root}}(Admin){{end}} {{.Path}}",
|
||||||
"blocks": [
|
"blocks": [
|
||||||
|
{
|
||||||
|
"type": "newline"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "prompt",
|
||||||
|
"alignment": "left",
|
||||||
|
"segments": [
|
||||||
{
|
{
|
||||||
"type":"newline"
|
"type": "root",
|
||||||
|
"style": "plain",
|
||||||
|
"foreground": "#BF616A",
|
||||||
|
"properties": {
|
||||||
|
"prefix": "",
|
||||||
|
"root_icon": "Admin"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type":"prompt",
|
"type": "path",
|
||||||
"alignment": "left",
|
"style": "plain",
|
||||||
"segments": [
|
"foreground": "#81A1C1",
|
||||||
{
|
"properties": {
|
||||||
"type":"root",
|
"prefix": "",
|
||||||
"style":"plain",
|
"style": "full"
|
||||||
"foreground": "#BF616A",
|
}
|
||||||
"properties": {
|
|
||||||
"prefix": "",
|
|
||||||
"root_icon": "Admin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type":"path",
|
|
||||||
"style":"plain",
|
|
||||||
"foreground": "#81A1C1",
|
|
||||||
"properties": {
|
|
||||||
"prefix": "",
|
|
||||||
"style": "full"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type":"prompt",
|
|
||||||
"alignment": "left",
|
|
||||||
"segments": [
|
|
||||||
{
|
|
||||||
"type":"git",
|
|
||||||
"style":"plain",
|
|
||||||
"foreground": "#6C6C6C",
|
|
||||||
"properties": {
|
|
||||||
"display_stash_count": true,
|
|
||||||
"display_status": true,
|
|
||||||
"display_status_detail": true,
|
|
||||||
"display_upstream_icon": true,
|
|
||||||
"branch_icon": "",
|
|
||||||
"github_icon": "",
|
|
||||||
"branch_ahead_icon": "<#88C0D0>\u21e1 </>",
|
|
||||||
"branch_behind_icon": "<#88C0D0>\u21e3 </>",
|
|
||||||
"local_working_icon": "<#FFAFD7>\u002a</>"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type":"prompt",
|
|
||||||
"alignment": "left",
|
|
||||||
"segments": [
|
|
||||||
{
|
|
||||||
"type":"executiontime",
|
|
||||||
"style":"plain",
|
|
||||||
"foreground": "#A3BE8C",
|
|
||||||
"properties": {
|
|
||||||
"style": "austin"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type":"newline"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alignment": "left",
|
|
||||||
"type":"prompt",
|
|
||||||
"segments": [
|
|
||||||
{
|
|
||||||
"type":"exit",
|
|
||||||
"style":"plain",
|
|
||||||
"foreground": "#B48EAD",
|
|
||||||
"properties": {
|
|
||||||
"prefix": "\u276f",
|
|
||||||
"display_exit_code": false,
|
|
||||||
"error_color": "#BF616A",
|
|
||||||
"always_enabled": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "prompt",
|
||||||
|
"alignment": "left",
|
||||||
|
"segments": [
|
||||||
|
{
|
||||||
|
"type": "git",
|
||||||
|
"style": "plain",
|
||||||
|
"foreground": "#6C6C6C",
|
||||||
|
"properties": {
|
||||||
|
"prefix": "",
|
||||||
|
"display_stash_count": true,
|
||||||
|
"display_status": true,
|
||||||
|
"display_status_detail": true,
|
||||||
|
"display_upstream_icon": true,
|
||||||
|
"branch_icon": "",
|
||||||
|
"github_icon": "",
|
||||||
|
"branch_ahead_icon": "<#88C0D0>\u21e1 </>",
|
||||||
|
"branch_behind_icon": "<#88C0D0>\u21e3 </>",
|
||||||
|
"local_working_icon": "<#FFAFD7>\u002a</>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "prompt",
|
||||||
|
"alignment": "left",
|
||||||
|
"segments": [
|
||||||
|
{
|
||||||
|
"type": "executiontime",
|
||||||
|
"style": "plain",
|
||||||
|
"foreground": "#A3BE8C",
|
||||||
|
"properties": {
|
||||||
|
"style": "austin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "newline"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alignment": "left",
|
||||||
|
"type": "prompt",
|
||||||
|
"segments": [
|
||||||
|
{
|
||||||
|
"type": "exit",
|
||||||
|
"style": "plain",
|
||||||
|
"foreground": "#B48EAD",
|
||||||
|
"properties": {
|
||||||
|
"prefix": "\u276f",
|
||||||
|
"display_exit_code": false,
|
||||||
|
"error_color": "#BF616A",
|
||||||
|
"always_enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"leading_diamond": "\uE0B6",
|
"leading_diamond": "\uE0B6",
|
||||||
"trailing_diamond": "",
|
"trailing_diamond": "",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"prefix": "",
|
||||||
"display_host":false
|
"display_host":false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
|
"$schema": "https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json",
|
||||||
"blocks": [
|
"blocks": [
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"wsl": "\ue712",
|
"wsl": "\ue712",
|
||||||
"wsl_separator": " on ",
|
"wsl_separator": " on ",
|
||||||
"windows": "\ue70f",
|
"windows": "\ue70f",
|
||||||
"postfix": "<#7a7a7a> \ue0b1</>"
|
"postfix": "<#7a7a7a> \uE0b1</>"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -177,7 +177,9 @@
|
||||||
"style": "plain",
|
"style": "plain",
|
||||||
"foreground": "#7a7a7a",
|
"foreground": "#7a7a7a",
|
||||||
"properties": {
|
"properties": {
|
||||||
"text": "~#@\u276F"
|
"text": "~#@\u276F",
|
||||||
|
"prefix": "",
|
||||||
|
"postfix": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
"style": "plain",
|
"style": "plain",
|
||||||
"foreground": "#0973C0",
|
"foreground": "#0973C0",
|
||||||
"properties": {
|
"properties": {
|
||||||
"style": "full"
|
"style": "full",
|
||||||
|
"prefix": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|