diff --git a/internal/config/settings.go b/internal/config/settings.go index 14e5f18b..7516dc68 100644 --- a/internal/config/settings.go +++ b/internal/config/settings.go @@ -101,6 +101,7 @@ var defaultCommonSettings = map[string]interface{}{ "tabstospaces": false, "useprimary": true, "wordwrap": false, + "wrapindent": float64(-1), } // a list of settings that should only be globally modified and their diff --git a/internal/display/bufwindow.go b/internal/display/bufwindow.go index 1ecb4323..ca05c2e1 100644 --- a/internal/display/bufwindow.go +++ b/internal/display/bufwindow.go @@ -432,6 +432,7 @@ func (w *BufWindow) displayBuffer() { softwrap := b.Settings["softwrap"].(bool) wordwrap := softwrap && b.Settings["wordwrap"].(bool) + wrapindent := util.IntOpt(w.Buf.Settings["wrapindent"]) tabsize := util.IntOpt(b.Settings["tabsize"]) colorcolumn := util.IntOpt(b.Settings["colorcolumn"]) @@ -699,11 +700,19 @@ func (w *BufWindow) displayBuffer() { if !softwrap { break } else { + // Get leading whitespaces before we wrap the line + ws := util.GetLeadingWhitespace(b.LineBytes(bloc.Y)) + vloc.Y++ if vloc.Y >= w.bufHeight { break } wrap() + + // After we wrapped the line, add the visual width of the leading whitespaces to the visual X column + if wrapindent > -1 { + vloc.X += util.StringWidth(ws, len(ws), tabsize) + wrapindent + } } } @@ -732,11 +741,19 @@ func (w *BufWindow) displayBuffer() { if !softwrap { break } else { + // Get leading whitespaces before we wrap the line + ws := util.GetLeadingWhitespace(b.LineBytes(bloc.Y)) + vloc.Y++ if vloc.Y >= w.bufHeight { break } wrap() + + // After we wrapped the line, add the visual width of the leading whitespaces to the visual X column + if wrapindent > -1 { + vloc.X += util.StringWidth(ws, len(ws), tabsize) + wrapindent + } } } } diff --git a/internal/display/softwrap.go b/internal/display/softwrap.go index 1460f883..1f00f72f 100644 --- a/internal/display/softwrap.go +++ b/internal/display/softwrap.go @@ -1,6 +1,8 @@ package display import ( + "bytes" + runewidth "github.com/mattn/go-runewidth" "github.com/zyedidia/micro/v2/internal/buffer" "github.com/zyedidia/micro/v2/internal/util" @@ -80,6 +82,7 @@ func (w *BufWindow) getVLocFromLoc(loc buffer.Loc) VLoc { wordwrap := w.Buf.Settings["wordwrap"].(bool) tabsize := util.IntOpt(w.Buf.Settings["tabsize"]) + leadingvisualspaces := w.getLeadingVisualSpaces(vloc) line := w.Buf.LineBytes(loc.Y) x := 0 @@ -121,6 +124,7 @@ func (w *BufWindow) getVLocFromLoc(loc buffer.Loc) VLoc { if vloc.VisualX+wordwidth > w.bufWidth && vloc.VisualX > 0 { vloc.Row++ vloc.VisualX = 0 + vloc.VisualX += leadingvisualspaces } if x == loc.X { @@ -137,6 +141,7 @@ func (w *BufWindow) getVLocFromLoc(loc buffer.Loc) VLoc { if vloc.VisualX >= w.bufWidth { vloc.Row++ vloc.VisualX = 0 + vloc.VisualX += leadingvisualspaces } } return vloc @@ -151,6 +156,7 @@ func (w *BufWindow) getLocFromVLoc(svloc VLoc) buffer.Loc { wordwrap := w.Buf.Settings["wordwrap"].(bool) tabsize := util.IntOpt(w.Buf.Settings["tabsize"]) + leadingvisualspaces := w.getLeadingVisualSpaces(svloc) line := w.Buf.LineBytes(svloc.Line) vloc := VLoc{SLoc: SLoc{svloc.Line, 0}, VisualX: 0} @@ -202,6 +208,7 @@ func (w *BufWindow) getLocFromVLoc(svloc VLoc) buffer.Loc { } vloc.Row++ vloc.VisualX = 0 + vloc.VisualX += leadingvisualspaces } for i := range widths { @@ -218,11 +225,24 @@ func (w *BufWindow) getLocFromVLoc(svloc VLoc) buffer.Loc { if vloc.VisualX >= w.bufWidth { vloc.Row++ vloc.VisualX = 0 + vloc.VisualX += leadingvisualspaces } } return loc } +// For wrapindent, count leading space to set correct VisualX on up, down action +func (w *BufWindow) getLeadingVisualSpaces(vloc VLoc) int { + wrapindent := util.IntOpt(w.Buf.Settings["wrapindent"]) + if wrapindent < 0 { + return 0 + } + line := w.Buf.LineBytes(vloc.Line) + leadingwhitespace := util.GetLeadingWhitespace(line) + leadingtabscount := bytes.Count(leadingwhitespace, []byte{'\t'}) + return wrapindent + leadingtabscount*int(w.Buf.Settings["tabsize"].(float64)) + (len(leadingwhitespace) - leadingtabscount) +} + func (w *BufWindow) getRowCount(line int) int { eol := buffer.Loc{X: util.CharacterCount(w.Buf.LineBytes(line)), Y: line} return w.getVLocFromLoc(eol).Row + 1 diff --git a/runtime/help/options.md b/runtime/help/options.md index e16d2259..7b9cdc83 100644 --- a/runtime/help/options.md +++ b/runtime/help/options.md @@ -473,6 +473,13 @@ Here are the available options: default value: `false` +* `wrapindent`: maintain indentation of wrapped lines + * `-1`: disabled, wrapped lines begin in the first column + * `0`: wrapped lines inherit indentation from parent + * `4`: creates additional hanging indent by this width + + default value: `-1` + * `xterm`: micro will assume that the terminal it is running in conforms to `xterm-256color` regardless of what the `$TERM` variable actually contains. Enabling this option may cause unwanted effects if your terminal in fact