From a8efe6fc5d44ac3108d96d95ddc1a94a79f6f73c Mon Sep 17 00:00:00 2001 From: Jan De Dobbeleer Date: Sun, 18 Apr 2021 19:16:06 +0200 Subject: [PATCH] feat: newline as part of block this deprecates the "newline" block and favours using the newline property on the Block component. For backwards compatibility we'll keep recognizing the newline block for the time being. resolves #607 --- .vscode/launch.json | 2 +- docs/docs/configuration.md | 15 +- src/block.go | 192 +++++++++++++++++++++ src/block_test.go | 29 ++++ src/config.go | 25 --- src/engine.go | 229 ++++++-------------------- src/segment.go | 11 ++ themes/agnosterplus.omp.json | 4 +- themes/avit.omp.json | 4 +- themes/blueish.omp.json | 4 +- themes/bubbles.omp.json | 4 +- themes/bubblesline.omp.json | 4 +- themes/cinnamon.omp.json | 4 +- themes/darkblood.omp.json | 4 +- themes/honukai.omp.json | 4 +- themes/huvix.omp.json | 8 +- themes/jonnychipz.omp.json | 14 +- themes/microverse-power.omp.json | 4 +- themes/negligible.omp.json | 4 +- themes/paradox.omp.json | 4 +- themes/pararussel.omp.json | 4 +- themes/pixelrobots.omp.json | 62 ++++--- themes/powerlevel10k_classic.omp.json | 4 +- themes/powerlevel10k_lean.omp.json | 4 +- themes/pure.omp.json | 10 +- themes/schema.json | 19 +-- themes/slim.omp.json | 4 +- themes/slimfat.omp.json | 4 +- themes/star.omp.json | 4 +- themes/stelbent.minimal.omp.json | 8 +- themes/ys.omp.json | 8 +- 31 files changed, 362 insertions(+), 338 deletions(-) create mode 100644 src/block.go create mode 100644 src/block_test.go diff --git a/.vscode/launch.json b/.vscode/launch.json index a038b85d67cc..30669ff13f39 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,7 +7,7 @@ "request": "launch", "mode": "debug", "program": "${workspaceRoot}/src", - "args": ["--config=/Users/jan/.jandedobbeleer.omp.json"] + "args": ["--config=${workspaceRoot}/themes/jandedobbeleer.omp.json"] }, { "name": "Launch tests", diff --git a/docs/docs/configuration.md b/docs/docs/configuration.md index e4ea79d40789..b68d754cbd43 100644 --- a/docs/docs/configuration.md +++ b/docs/docs/configuration.md @@ -105,7 +105,8 @@ the current working directory is `/usr/home/omp` and the shell is `zsh`. Let's take a closer look at what defines a block. -- type: `prompt` | `rprompt` | `newline` +- type: `prompt` | `rprompt` +- newline: `boolean` - alignment: `left` | `right` - vertical_offset: `int` - horizontal_offset: `int` @@ -117,9 +118,11 @@ Tells the engine what to do with the block. There are three options: - `prompt` renders one or more segments - `rprompt` renders one or more segments aligned to the right of the cursor. Only one `rprompt` block is permitted. -Supported on [ZSH][rprompt] and Powershell. -- `newline` inserts a new line to start the next block on a new line. `newline` blocks require no additional -configuration other than the `type`. +Supported on [ZSH][rprompt], Bash and Powershell. + +### Newline + +Start the block on a new line. Defaults to `false`. ### Alignment @@ -402,12 +405,10 @@ has to be enabled at the segment level. Hyperlink generation is disabled by defa } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "session", diff --git a/src/block.go b/src/block.go new file mode 100644 index 000000000000..efc08680ed88 --- /dev/null +++ b/src/block.go @@ -0,0 +1,192 @@ +package main + +import ( + "fmt" + "sync" + "time" +) + +// BlockType type of block +type BlockType string + +// BlockAlignment aligment of a Block +type BlockAlignment string + +const ( + // Prompt writes one or more Segments + Prompt BlockType = "prompt" + // LineBreak creates a line break in the prompt + LineBreak BlockType = "newline" + // RPrompt a right aligned prompt in ZSH and Powershell + RPrompt BlockType = "rprompt" + // Left aligns left + Left BlockAlignment = "left" + // Right aligns right + Right BlockAlignment = "right" +) + +// Block defines a part of the prompt with optional segments +type Block struct { + Type BlockType `config:"type"` + Alignment BlockAlignment `config:"alignment"` + HorizontalOffset int `config:"horizontal_offset"` + VerticalOffset int `config:"vertical_offset"` + Segments []*Segment `config:"segments"` + Newline bool `config:"newline"` + + env environmentInfo + color *AnsiColor + activeSegment *Segment + previousActiveSegment *Segment +} + +func (b *Block) init(env environmentInfo, color *AnsiColor) { + b.env = env + b.color = color +} + +func (b *Block) enabled() bool { + if b.Type == LineBreak { + return true + } + for _, segment := range b.Segments { + if segment.active { + return true + } + } + return false +} + +func (b *Block) setStringValues() { + wg := sync.WaitGroup{} + wg.Add(len(b.Segments)) + defer wg.Wait() + cwd := b.env.getcwd() + for _, segment := range b.Segments { + go func(s *Segment) { + defer wg.Done() + s.setStringValue(b.env, cwd) + }(segment) + } +} + +func (b *Block) renderSegments() string { + for _, segment := range b.Segments { + if !segment.active { + continue + } + b.activeSegment = segment + b.endPowerline() + b.renderSegmentText(segment.stringValue) + } + if b.previousActiveSegment != nil && b.previousActiveSegment.Style == Powerline { + b.writePowerLineSeparator(Transparent, b.previousActiveSegment.background(), true) + } + return b.color.string() +} + +func (b *Block) endPowerline() { + if b.activeSegment != nil && + b.activeSegment.Style != Powerline && + b.previousActiveSegment != nil && + b.previousActiveSegment.Style == Powerline { + b.writePowerLineSeparator(b.getPowerlineColor(false), b.previousActiveSegment.background(), true) + } +} + +func (b *Block) writePowerLineSeparator(background, foreground string, end bool) { + symbol := b.activeSegment.PowerlineSymbol + if end { + symbol = b.previousActiveSegment.PowerlineSymbol + } + if b.activeSegment.InvertPowerline { + b.color.write(foreground, background, symbol) + return + } + b.color.write(background, foreground, symbol) +} + +func (b *Block) getPowerlineColor(foreground bool) string { + if b.previousActiveSegment == nil { + return Transparent + } + if !foreground && b.activeSegment.Style != Powerline { + return Transparent + } + if foreground && b.previousActiveSegment.Style != Powerline { + return Transparent + } + return b.previousActiveSegment.background() +} + +func (b *Block) renderSegmentText(text string) { + switch b.activeSegment.Style { + case Plain: + b.renderPlainSegment(text) + case Diamond: + b.renderDiamondSegment(text) + case Powerline: + b.renderPowerLineSegment(text) + } + b.previousActiveSegment = b.activeSegment +} + +func (b *Block) renderPowerLineSegment(text string) { + b.writePowerLineSeparator(b.activeSegment.background(), b.getPowerlineColor(true), false) + b.renderText(text) +} + +func (b *Block) renderPlainSegment(text string) { + b.renderText(text) +} + +func (b *Block) renderDiamondSegment(text string) { + b.color.write(Transparent, b.activeSegment.background(), b.activeSegment.LeadingDiamond) + b.renderText(text) + b.color.write(Transparent, b.activeSegment.background(), b.activeSegment.TrailingDiamond) +} + +func (b *Block) renderText(text string) { + text = b.color.formats.generateHyperlink(text) + defaultValue := " " + prefix := b.activeSegment.getValue(Prefix, defaultValue) + postfix := b.activeSegment.getValue(Postfix, defaultValue) + b.color.write(b.activeSegment.background(), b.activeSegment.foreground(), fmt.Sprintf("%s%s%s", prefix, text, postfix)) +} + +func (b *Block) debug() (int, []*SegmentTiming) { + var segmentTimings []*SegmentTiming + largestSegmentNameLength := 0 + for _, segment := range b.Segments { + err := segment.mapSegmentWithWriter(b.env) + if err != nil || !segment.shouldIncludeFolder(b.env.getcwd()) { + continue + } + var segmentTiming SegmentTiming + segmentTiming.name = string(segment.Type) + segmentTiming.nameLength = len(segmentTiming.name) + if segmentTiming.nameLength > largestSegmentNameLength { + largestSegmentNameLength = segmentTiming.nameLength + } + // enabled() timing + start := time.Now() + segmentTiming.enabled = segment.enabled() + segmentTiming.enabledDuration = time.Since(start) + // string() timing + if segmentTiming.enabled { + start = time.Now() + segmentTiming.stringValue = segment.string() + segmentTiming.stringDuration = time.Since(start) + b.previousActiveSegment = nil + b.activeSegment = segment + b.renderSegmentText(segmentTiming.stringValue) + if b.activeSegment.Style == Powerline { + b.writePowerLineSeparator(Transparent, b.activeSegment.background(), true) + } + segmentTiming.stringValue = b.color.string() + b.color.builder.Reset() + } + segmentTimings = append(segmentTimings, &segmentTiming) + } + return largestSegmentNameLength, segmentTimings +} diff --git a/src/block_test.go b/src/block_test.go new file mode 100644 index 000000000000..863d8515a70b --- /dev/null +++ b/src/block_test.go @@ -0,0 +1,29 @@ +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestBlockEnabled(t *testing.T) { + cases := []struct { + Case string + Expected bool + Segments []*Segment + Type BlockType + }{ + {Case: "line break block", Expected: true, Type: LineBreak}, + {Case: "prompt enabled", Expected: true, Type: Prompt, Segments: []*Segment{{active: true}}}, + {Case: "prompt disabled", Expected: false, Type: Prompt, Segments: []*Segment{{active: false}}}, + {Case: "prompt enabled multiple", Expected: true, Type: Prompt, Segments: []*Segment{{active: false}, {active: true}}}, + {Case: "rprompt enabled multiple", Expected: true, Type: RPrompt, Segments: []*Segment{{active: false}, {active: true}}}, + } + for _, tc := range cases { + block := &Block{ + Type: tc.Type, + Segments: tc.Segments, + } + assert.Equal(t, tc.Expected, block.enabled(), tc.Case) + } +} diff --git a/src/config.go b/src/config.go index a559ef303bb7..4fcd6576dcd6 100644 --- a/src/config.go +++ b/src/config.go @@ -28,36 +28,11 @@ type Config struct { Blocks []*Block `config:"blocks"` } -// BlockType type of block -type BlockType string - -// BlockAlignment aligment of a Block -type BlockAlignment string - const ( - // Prompt writes one or more Segments - Prompt BlockType = "prompt" - // LineBreak creates a line break in the prompt - LineBreak BlockType = "newline" - // RPrompt a right aligned prompt in ZSH and Powershell - RPrompt BlockType = "rprompt" - // Left aligns left - Left BlockAlignment = "left" - // Right aligns right - Right BlockAlignment = "right" // EnableHyperlink enable hyperlink EnableHyperlink Property = "enable_hyperlink" ) -// Block defines a part of the prompt with optional segments -type Block struct { - Type BlockType `config:"type"` - Alignment BlockAlignment `config:"alignment"` - HorizontalOffset int `config:"horizontal_offset"` - VerticalOffset int `config:"vertical_offset"` - Segments []*Segment `config:"segments"` -} - // GetConfig returns the default configuration including possible user overrides func GetConfig(env environmentInfo) *Config { cfg, err := loadConfig(env) diff --git a/src/engine.go b/src/engine.go index ff6f69f888ba..56ea8ae3684e 100644 --- a/src/engine.go +++ b/src/engine.go @@ -3,154 +3,24 @@ package main import ( "fmt" "strings" - "sync" "time" ) type engine struct { - config *Config - env environmentInfo - color *AnsiColor - renderer *AnsiRenderer - consoleTitle *consoleTitle - activeBlock *Block - activeSegment *Segment - previousActiveSegment *Segment - rprompt string -} - -// SegmentTiming holds the timing context for a segment -type SegmentTiming struct { - name string - nameLength int - enabled bool - stringValue string - enabledDuration time.Duration - stringDuration time.Duration -} - -func (e *engine) getPowerlineColor(foreground bool) string { - if e.previousActiveSegment == nil { - return Transparent - } - if !foreground && e.activeSegment.Style != Powerline { - return Transparent - } - if foreground && e.previousActiveSegment.Style != Powerline { - return Transparent - } - return e.previousActiveSegment.background() -} - -func (e *engine) writePowerLineSeparator(background, foreground string, end bool) { - symbol := e.activeSegment.PowerlineSymbol - if end { - symbol = e.previousActiveSegment.PowerlineSymbol - } - if e.activeSegment.InvertPowerline { - e.color.write(foreground, background, symbol) - return - } - e.color.write(background, foreground, symbol) -} - -func (e *engine) endPowerline() { - if e.activeSegment != nil && - e.activeSegment.Style != Powerline && - e.previousActiveSegment != nil && - e.previousActiveSegment.Style == Powerline { - e.writePowerLineSeparator(e.getPowerlineColor(false), e.previousActiveSegment.background(), true) - } -} - -func (e *engine) renderPowerLineSegment(text string) { - e.writePowerLineSeparator(e.activeSegment.background(), e.getPowerlineColor(true), false) - e.renderText(text) -} - -func (e *engine) renderPlainSegment(text string) { - e.renderText(text) -} - -func (e *engine) renderDiamondSegment(text string) { - e.color.write(Transparent, e.activeSegment.background(), e.activeSegment.LeadingDiamond) - e.renderText(text) - e.color.write(Transparent, e.activeSegment.background(), e.activeSegment.TrailingDiamond) -} - -func (e *engine) renderText(text string) { - text = e.color.formats.generateHyperlink(text) - defaultValue := " " - prefix := e.activeSegment.getValue(Prefix, defaultValue) - postfix := e.activeSegment.getValue(Postfix, defaultValue) - e.color.write(e.activeSegment.background(), e.activeSegment.foreground(), fmt.Sprintf("%s%s%s", prefix, text, postfix)) -} - -func (e *engine) renderSegmentText(text string) { - switch e.activeSegment.Style { - case Plain: - e.renderPlainSegment(text) - case Diamond: - e.renderDiamondSegment(text) - case Powerline: - e.renderPowerLineSegment(text) - } - e.previousActiveSegment = e.activeSegment -} - -func (e *engine) renderBlockSegments(block *Block) string { - defer e.resetBlock() - e.activeBlock = block - e.setStringValues(block.Segments) - for _, segment := range block.Segments { - if !segment.active { - continue - } - e.activeSegment = segment - e.endPowerline() - e.renderSegmentText(segment.stringValue) - } - if e.previousActiveSegment != nil && e.previousActiveSegment.Style == Powerline { - e.writePowerLineSeparator(Transparent, e.previousActiveSegment.background(), true) - } - return e.color.string() -} - -func (e *engine) setStringValues(segments []*Segment) { - wg := sync.WaitGroup{} - wg.Add(len(segments)) - defer wg.Wait() - cwd := e.env.getcwd() - for _, segment := range segments { - go func(s *Segment) { - defer wg.Done() - s.setStringValue(e.env, cwd) - }(segment) - } + config *Config + env environmentInfo + color *AnsiColor + renderer *AnsiRenderer + consoleTitle *consoleTitle + // activeBlock *Block + // activeSegment *Segment + // previousActiveSegment *Segment + rprompt string } func (e *engine) render() string { for _, block := range e.config.Blocks { - // if line break, append a line break - switch block.Type { - case LineBreak: - e.renderer.write("\n") - case Prompt: - if block.VerticalOffset != 0 { - e.renderer.changeLine(block.VerticalOffset) - } - switch block.Alignment { - case Right: - e.renderer.carriageForward() - blockText := e.renderBlockSegments(block) - e.renderer.setCursorForRightWrite(blockText, block.HorizontalOffset) - e.renderer.write(blockText) - case Left: - e.renderer.write(e.renderBlockSegments(block)) - } - case RPrompt: - e.rprompt = e.renderBlockSegments(block) - } + e.renderBlock(block) } if e.config.ConsoleTitle { e.renderer.write(e.consoleTitle.getConsoleTitle()) @@ -171,9 +41,43 @@ func (e *engine) render() string { return e.print() } +func (e *engine) renderBlock(block *Block) { + block.init(e.env, e.color) + block.setStringValues() + defer e.color.reset() + if !block.enabled() { + return + } + if block.Newline { + e.renderer.write("\n") + } + switch block.Type { + // This is deprecated but leave if to not break current configs + // It is encouraged to used "newline": true on block level + // rather than the standalone the linebreak block + case LineBreak: + e.renderer.write("\n") + case Prompt: + if block.VerticalOffset != 0 { + e.renderer.changeLine(block.VerticalOffset) + } + switch block.Alignment { + case Right: + e.renderer.carriageForward() + blockText := block.renderSegments() + e.renderer.setCursorForRightWrite(blockText, block.HorizontalOffset) + e.renderer.write(blockText) + case Left: + e.renderer.write(block.renderSegments()) + } + case RPrompt: + e.rprompt = block.renderSegments() + } +} + // debug will loop through your config file and output the timings for each segments func (e *engine) debug() string { - var segmentTimings []SegmentTiming + var segmentTimings []*SegmentTiming largestSegmentNameLength := 0 e.renderer.write("\n\x1b[1mHere are the timings of segments in your prompt:\x1b[0m\n\n") @@ -181,7 +85,7 @@ func (e *engine) debug() string { start := time.Now() consoleTitle := e.consoleTitle.getTemplateText() duration := time.Since(start) - segmentTiming := SegmentTiming{ + segmentTiming := &SegmentTiming{ name: "ConsoleTitle", nameLength: 12, enabled: e.config.ConsoleTitle, @@ -192,36 +96,11 @@ func (e *engine) debug() string { segmentTimings = append(segmentTimings, segmentTiming) // loop each segments of each blocks for _, block := range e.config.Blocks { - for _, segment := range block.Segments { - err := segment.mapSegmentWithWriter(e.env) - if err != nil || !segment.shouldIncludeFolder(e.env.getcwd()) { - continue - } - var segmentTiming SegmentTiming - segmentTiming.name = string(segment.Type) - segmentTiming.nameLength = len(segmentTiming.name) - if segmentTiming.nameLength > largestSegmentNameLength { - largestSegmentNameLength = segmentTiming.nameLength - } - // enabled() timing - start := time.Now() - segmentTiming.enabled = segment.enabled() - segmentTiming.enabledDuration = time.Since(start) - // string() timing - if segmentTiming.enabled { - start = time.Now() - segmentTiming.stringValue = segment.string() - segmentTiming.stringDuration = time.Since(start) - e.previousActiveSegment = nil - e.activeSegment = segment - e.renderSegmentText(segmentTiming.stringValue) - if e.activeSegment.Style == Powerline { - e.writePowerLineSeparator(Transparent, e.activeSegment.background(), true) - } - segmentTiming.stringValue = e.color.string() - e.color.builder.Reset() - } - segmentTimings = append(segmentTimings, segmentTiming) + block.init(e.env, e.color) + longestSegmentName, timings := block.debug() + segmentTimings = append(segmentTimings, timings...) + if longestSegmentName > largestSegmentNameLength { + largestSegmentNameLength = longestSegmentName } } @@ -258,9 +137,3 @@ func (e *engine) print() string { } return e.renderer.string() } - -func (e *engine) resetBlock() { - e.color.reset() - e.previousActiveSegment = nil - e.activeBlock = nil -} diff --git a/src/segment.go b/src/segment.go index c50e901846ea..4e0d5c04efe2 100644 --- a/src/segment.go +++ b/src/segment.go @@ -3,6 +3,7 @@ package main import ( "errors" "fmt" + "time" ) // Segment represent a single segment and it's configuration @@ -24,6 +25,16 @@ type Segment struct { active bool } +// SegmentTiming holds the timing context for a segment +type SegmentTiming struct { + name string + nameLength int + enabled bool + stringValue string + enabledDuration time.Duration + stringDuration time.Duration +} + // SegmentWriter is the interface used to define what and if to write to the prompt type SegmentWriter interface { enabled() bool diff --git a/themes/agnosterplus.omp.json b/themes/agnosterplus.omp.json index 210f4152b686..97488a009828 100644 --- a/themes/agnosterplus.omp.json +++ b/themes/agnosterplus.omp.json @@ -16,12 +16,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "session", diff --git a/themes/avit.omp.json b/themes/avit.omp.json index 710a81f0d3a2..ad7a60e13660 100644 --- a/themes/avit.omp.json +++ b/themes/avit.omp.json @@ -34,12 +34,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/blueish.omp.json b/themes/blueish.omp.json index 5845b8812c0e..3adde2640633 100644 --- a/themes/blueish.omp.json +++ b/themes/blueish.omp.json @@ -107,11 +107,9 @@ ] }, { - "type": "newline" - }, - { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/bubbles.omp.json b/themes/bubbles.omp.json index 8fcad407b650..47660bea52ec 100644 --- a/themes/bubbles.omp.json +++ b/themes/bubbles.omp.json @@ -146,12 +146,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "executiontime", diff --git a/themes/bubblesline.omp.json b/themes/bubblesline.omp.json index 44265d7abcc8..61efb00f2803 100644 --- a/themes/bubblesline.omp.json +++ b/themes/bubblesline.omp.json @@ -133,12 +133,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "session", diff --git a/themes/cinnamon.omp.json b/themes/cinnamon.omp.json index 52d1bbf304c0..56ae76a64881 100644 --- a/themes/cinnamon.omp.json +++ b/themes/cinnamon.omp.json @@ -38,12 +38,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/darkblood.omp.json b/themes/darkblood.omp.json index 39b9a2f08c33..f452ec4efada 100644 --- a/themes/darkblood.omp.json +++ b/themes/darkblood.omp.json @@ -45,12 +45,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "path", diff --git a/themes/honukai.omp.json b/themes/honukai.omp.json index 62cd8496e67c..15ec2cf87018 100644 --- a/themes/honukai.omp.json +++ b/themes/honukai.omp.json @@ -51,12 +51,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "root", diff --git a/themes/huvix.omp.json b/themes/huvix.omp.json index e6c88e6ae61a..e0d1a1632d1c 100644 --- a/themes/huvix.omp.json +++ b/themes/huvix.omp.json @@ -39,7 +39,7 @@ "foreground": "#9e7eff", "properties": { "prefix": "\u0028\uE235 ", - "postfix": "\u0029 " + "postfix": "\u0029 " } }, { @@ -67,12 +67,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "battery", @@ -97,4 +95,4 @@ ], "final_space": true } - + diff --git a/themes/jonnychipz.omp.json b/themes/jonnychipz.omp.json index 6ef5f2c8a8eb..ec80839274b2 100644 --- a/themes/jonnychipz.omp.json +++ b/themes/jonnychipz.omp.json @@ -20,7 +20,7 @@ "postfix": "", "prefix": "" } - }, + }, { "type": "session", "style": "diamond", @@ -42,7 +42,7 @@ "prefix": " \uFD03 " } }, - + { "type": "exit", "style": "diamond", @@ -60,13 +60,11 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", - "segments": [ + "newline": true, + "segments": [ { "type": "os", "style": "diamond", @@ -94,7 +92,7 @@ "postfix": "<#000000> \ue0b1" } }, - + { "type": "root", "style": "diamond", @@ -174,4 +172,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/themes/microverse-power.omp.json b/themes/microverse-power.omp.json index 4aca65f33b5a..748b924167a6 100644 --- a/themes/microverse-power.omp.json +++ b/themes/microverse-power.omp.json @@ -86,12 +86,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/negligible.omp.json b/themes/negligible.omp.json index c5e192f7d9cd..88331b388cc3 100644 --- a/themes/negligible.omp.json +++ b/themes/negligible.omp.json @@ -56,12 +56,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "exit", diff --git a/themes/paradox.omp.json b/themes/paradox.omp.json index 48c2263a1865..153e0611ae22 100644 --- a/themes/paradox.omp.json +++ b/themes/paradox.omp.json @@ -60,12 +60,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/pararussel.omp.json b/themes/pararussel.omp.json index 1bf35f4b0d5b..e05755ac67d6 100644 --- a/themes/pararussel.omp.json +++ b/themes/pararussel.omp.json @@ -60,12 +60,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/pixelrobots.omp.json b/themes/pixelrobots.omp.json index 823e47a2e389..6330a7cdd348 100644 --- a/themes/pixelrobots.omp.json +++ b/themes/pixelrobots.omp.json @@ -22,38 +22,36 @@ } }, { - "type": "kubectl", - "style": "powerline", - "powerline_symbol": "", - "foreground": "#000000", - "background": "#ffea00", - "properties": { - "prefix": " \uFD31", - "template": " {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}" - } - }, - { - "type": "az", - "style": "powerline", - "powerline_symbol": "\uE0B0", - "foreground": "#000000", - "background": "#008AD7", - "properties": { - "display_id": false, - "display_name": true, - "info_separator": " @ ", - "prefix": " \uFD03 " - } - } - ] + "type": "kubectl", + "style": "powerline", + "powerline_symbol": "", + "foreground": "#000000", + "background": "#ffea00", + "properties": { + "prefix": " \uFD31", + "template": " {{.Context}}{{if .Namespace}} :: {{.Namespace}}{{end}}" + } + }, + { + "type": "az", + "style": "powerline", + "powerline_symbol": "\uE0B0", + "foreground": "#000000", + "background": "#008AD7", + "properties": { + "display_id": false, + "display_name": true, + "info_separator": " @ ", + "prefix": " \uFD03 " + } + } + ] }, - { - "type": "newline" - }, - { - "type": "prompt", - "alignment": "left", - "segments": [ + { + "type": "prompt", + "alignment": "left", + "newline": true, + "segments": [ { "type": "os", "style": "diamond", @@ -167,4 +165,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/themes/powerlevel10k_classic.omp.json b/themes/powerlevel10k_classic.omp.json index 6348f71cb46d..16e303b3b62d 100644 --- a/themes/powerlevel10k_classic.omp.json +++ b/themes/powerlevel10k_classic.omp.json @@ -78,12 +78,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "exit", diff --git a/themes/powerlevel10k_lean.omp.json b/themes/powerlevel10k_lean.omp.json index 774f3bae9047..0c959866c497 100644 --- a/themes/powerlevel10k_lean.omp.json +++ b/themes/powerlevel10k_lean.omp.json @@ -16,12 +16,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "path", diff --git a/themes/pure.omp.json b/themes/pure.omp.json index 7117e63ad422..dacec272be60 100644 --- a/themes/pure.omp.json +++ b/themes/pure.omp.json @@ -4,12 +4,10 @@ "console_title_style": "template", "console_title_template": "{{if .Root}}(Admin){{end}} {{.Path}}", "blocks": [ - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "root", @@ -69,11 +67,9 @@ ] }, { - "type": "newline" - }, - { - "alignment": "left", "type": "prompt", + "alignment": "left", + "newline": true, "segments": [ { "type": "exit", diff --git a/themes/schema.json b/themes/schema.json index de4357e46641..34c75898094f 100644 --- a/themes/schema.json +++ b/themes/schema.json @@ -50,17 +50,6 @@ "type": "object", "description": "https://ohmyposh.dev/docs/configure#block", "allOf": [ - { - "if": { - "properties": { - "type": { "const": "newline" } - } - }, - "then": { - "required": ["type"], - "title": "Newline, renders a line break" - } - }, { "if": { "properties": { @@ -89,7 +78,7 @@ "type": "string", "title": "Block type", "description": "https://ohmyposh.dev/docs/configure#type", - "enum": ["prompt", "rprompt", "newline"], + "enum": ["prompt", "rprompt"], "default": "prompt" }, "alignment": { @@ -99,6 +88,12 @@ "enum": ["left", "right"], "default": "left" }, + "newline": { + "type": "boolean", + "title": "Newline", + "description": "https://ohmyposh.dev/docs/configure#newline", + "default": false + }, "vertical_offset": { "type": "integer", "title": "Block vertical offset", diff --git a/themes/slim.omp.json b/themes/slim.omp.json index c550ef94f835..f9ceb6cfcac9 100644 --- a/themes/slim.omp.json +++ b/themes/slim.omp.json @@ -165,12 +165,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/slimfat.omp.json b/themes/slimfat.omp.json index a3fdaf292063..0ad306933075 100644 --- a/themes/slimfat.omp.json +++ b/themes/slimfat.omp.json @@ -163,12 +163,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/star.omp.json b/themes/star.omp.json index 209a3db34331..fb7751a78714 100644 --- a/themes/star.omp.json +++ b/themes/star.omp.json @@ -53,12 +53,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/stelbent.minimal.omp.json b/themes/stelbent.minimal.omp.json index b7c2fae8df15..be3e8bfcc468 100644 --- a/themes/stelbent.minimal.omp.json +++ b/themes/stelbent.minimal.omp.json @@ -37,12 +37,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "session", @@ -117,12 +115,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", diff --git a/themes/ys.omp.json b/themes/ys.omp.json index 75267131b4f6..d9ae5e07c081 100644 --- a/themes/ys.omp.json +++ b/themes/ys.omp.json @@ -17,12 +17,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text", @@ -87,12 +85,10 @@ } ] }, - { - "type": "newline" - }, { "type": "prompt", "alignment": "left", + "newline": true, "segments": [ { "type": "text",