Add --no-unicode option to draw borders in ASCII characters

Close ##1533
This commit is contained in:
Junegunn Choi 2019-03-29 02:11:03 +09:00
parent e7d60aac9c
commit 75972d59a8
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
6 changed files with 87 additions and 38 deletions

View File

@ -174,6 +174,11 @@ A synonym for \fB--layout=reverse\fB
.TP .TP
.B "--border" .B "--border"
Draw border above and below the finder Draw border above and below the finder
.TP
.B "--no-unicode"
Use ASCII characters instead of Unicode box drawing characters to draw border
.TP .TP
.BI "--margin=" MARGIN .BI "--margin=" MARGIN
Comma-separated expression for margins around the finder. Comma-separated expression for margins around the finder.

View File

@ -195,6 +195,7 @@ type Options struct {
HeaderLines int HeaderLines int
Margin [4]sizeSpec Margin [4]sizeSpec
Bordered bool Bordered bool
Unicode bool
Tabstop int Tabstop int
ClearOnExit bool ClearOnExit bool
Version bool Version bool
@ -244,6 +245,7 @@ func defaultOptions() *Options {
Header: make([]string, 0), Header: make([]string, 0),
HeaderLines: 0, HeaderLines: 0,
Margin: defaultMargin(), Margin: defaultMargin(),
Unicode: true,
Tabstop: 8, Tabstop: 8,
ClearOnExit: true, ClearOnExit: true,
Version: false} Version: false}
@ -1152,6 +1154,10 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Bordered = false opts.Bordered = false
case "--border": case "--border":
opts.Bordered = true opts.Bordered = true
case "--no-unicode":
opts.Unicode = false
case "--unicode":
opts.Unicode = true
case "--margin": case "--margin":
opts.Margin = parseMargin( opts.Margin = parseMargin(
nextString(allArgs, &i, "margin required (TRBL / TB,RL / T,RL,B / T,R,B,L)")) nextString(allArgs, &i, "margin required (TRBL / TB,RL / T,RL,B / T,R,B,L)"))

View File

@ -88,6 +88,7 @@ type Terminal struct {
tabstop int tabstop int
margin [4]sizeSpec margin [4]sizeSpec
strong tui.Attr strong tui.Attr
unicode bool
bordered bool bordered bool
cleanExit bool cleanExit bool
border tui.Window border tui.Window
@ -391,6 +392,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
printQuery: opts.PrintQuery, printQuery: opts.PrintQuery,
history: opts.History, history: opts.History,
margin: opts.Margin, margin: opts.Margin,
unicode: opts.Unicode,
bordered: opts.Bordered, bordered: opts.Bordered,
cleanExit: opts.ClearOnExit, cleanExit: opts.ClearOnExit,
strong: strongAttr, strong: strongAttr,
@ -600,11 +602,12 @@ func (t *Terminal) resizeWindows() {
marginInt[0]-1, marginInt[0]-1,
marginInt[3], marginInt[3],
width, width,
height+2, tui.BorderHorizontal) height+2, tui.MakeBorderStyle(tui.BorderHorizontal, t.unicode))
} }
noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode)
if previewVisible { if previewVisible {
createPreviewWindow := func(y int, x int, w int, h int) { createPreviewWindow := func(y int, x int, w int, h int) {
t.pborder = t.tui.NewWindow(y, x, w, h, tui.BorderAround) t.pborder = t.tui.NewWindow(y, x, w, h, tui.MakeBorderStyle(tui.BorderAround, t.unicode))
pwidth := w - 4 pwidth := w - 4
// ncurses auto-wraps the line when the cursor reaches the right-end of // ncurses auto-wraps the line when the cursor reaches the right-end of
// the window. To prevent unintended line-wraps, we use the width one // the window. To prevent unintended line-wraps, we use the width one
@ -612,28 +615,28 @@ func (t *Terminal) resizeWindows() {
if !t.preview.wrap && t.tui.DoesAutoWrap() { if !t.preview.wrap && t.tui.DoesAutoWrap() {
pwidth += 1 pwidth += 1
} }
t.pwindow = t.tui.NewWindow(y+1, x+2, pwidth, h-2, tui.BorderNone) t.pwindow = t.tui.NewWindow(y+1, x+2, pwidth, h-2, noBorder)
} }
switch t.preview.position { switch t.preview.position {
case posUp: case posUp:
pheight := calculateSize(height, t.preview.size, minHeight, 3) pheight := calculateSize(height, t.preview.size, minHeight, 3)
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0]+pheight, marginInt[3], width, height-pheight, tui.BorderNone) marginInt[0]+pheight, marginInt[3], width, height-pheight, noBorder)
createPreviewWindow(marginInt[0], marginInt[3], width, pheight) createPreviewWindow(marginInt[0], marginInt[3], width, pheight)
case posDown: case posDown:
pheight := calculateSize(height, t.preview.size, minHeight, 3) pheight := calculateSize(height, t.preview.size, minHeight, 3)
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width, height-pheight, tui.BorderNone) marginInt[0], marginInt[3], width, height-pheight, noBorder)
createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight) createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight)
case posLeft: case posLeft:
pwidth := calculateSize(width, t.preview.size, minWidth, 5) pwidth := calculateSize(width, t.preview.size, minWidth, 5)
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0], marginInt[3]+pwidth, width-pwidth, height, tui.BorderNone) marginInt[0], marginInt[3]+pwidth, width-pwidth, height, noBorder)
createPreviewWindow(marginInt[0], marginInt[3], pwidth, height) createPreviewWindow(marginInt[0], marginInt[3], pwidth, height)
case posRight: case posRight:
pwidth := calculateSize(width, t.preview.size, minWidth, 5) pwidth := calculateSize(width, t.preview.size, minWidth, 5)
t.window = t.tui.NewWindow( t.window = t.tui.NewWindow(
marginInt[0], marginInt[3], width-pwidth, height, tui.BorderNone) marginInt[0], marginInt[3], width-pwidth, height, noBorder)
createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height) createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height)
} }
} else { } else {
@ -641,7 +644,7 @@ func (t *Terminal) resizeWindows() {
marginInt[0], marginInt[0],
marginInt[3], marginInt[3],
width, width,
height, tui.BorderNone) height, noBorder)
} }
for i := 0; i < t.window.Height(); i++ { for i := 0; i < t.window.Height(); i++ {
t.window.MoveAndClear(i, 0) t.window.MoveAndClear(i, 0)

View File

@ -163,9 +163,9 @@ func (r *LightRenderer) findOffset() (row int, col int) {
return -1, -1 return -1, -1
} }
func repeat(s string, times int) string { func repeat(r rune, times int) string {
if times > 0 { if times > 0 {
return strings.Repeat(s, times) return strings.Repeat(string(r), times)
} }
return "" return ""
} }
@ -676,7 +676,7 @@ func (r *LightRenderer) NewWindow(top int, left int, width int, height int, bord
} }
func (w *LightWindow) drawBorder() { func (w *LightWindow) drawBorder() {
switch w.border { switch w.border.shape {
case BorderAround: case BorderAround:
w.drawBorderAround() w.drawBorderAround()
case BorderHorizontal: case BorderHorizontal:
@ -686,22 +686,24 @@ func (w *LightWindow) drawBorder() {
func (w *LightWindow) drawBorderHorizontal() { func (w *LightWindow) drawBorderHorizontal() {
w.Move(0, 0) w.Move(0, 0)
w.CPrint(ColBorder, AttrRegular, repeat("─", w.width)) w.CPrint(ColBorder, AttrRegular, repeat(w.border.horizontal, w.width))
w.Move(w.height-1, 0) w.Move(w.height-1, 0)
w.CPrint(ColBorder, AttrRegular, repeat("─", w.width)) w.CPrint(ColBorder, AttrRegular, repeat(w.border.horizontal, w.width))
} }
func (w *LightWindow) drawBorderAround() { func (w *LightWindow) drawBorderAround() {
w.Move(0, 0) w.Move(0, 0)
w.CPrint(ColBorder, AttrRegular, "┌"+repeat("─", w.width-2)+"┐") w.CPrint(ColBorder, AttrRegular,
string(w.border.topLeft)+repeat(w.border.horizontal, w.width-2)+string(w.border.topRight))
for y := 1; y < w.height-1; y++ { for y := 1; y < w.height-1; y++ {
w.Move(y, 0) w.Move(y, 0)
w.CPrint(ColBorder, AttrRegular, "│") w.CPrint(ColBorder, AttrRegular, string(w.border.vertical))
w.cprint2(colDefault, w.bg, AttrRegular, repeat(" ", w.width-2)) w.cprint2(colDefault, w.bg, AttrRegular, repeat(' ', w.width-2))
w.CPrint(ColBorder, AttrRegular, "│") w.CPrint(ColBorder, AttrRegular, string(w.border.vertical))
} }
w.Move(w.height-1, 0) w.Move(w.height-1, 0)
w.CPrint(ColBorder, AttrRegular, "└"+repeat("─", w.width-2)+"┘") w.CPrint(ColBorder, AttrRegular,
string(w.border.bottomLeft)+repeat(w.border.horizontal, w.width-2)+string(w.border.bottomRight))
} }
func (w *LightWindow) csi(code string) { func (w *LightWindow) csi(code string) {
@ -762,7 +764,7 @@ func (w *LightWindow) MoveAndClear(y int, x int) {
w.Move(y, x) w.Move(y, x)
// We should not delete preview window on the right // We should not delete preview window on the right
// csi("K") // csi("K")
w.Print(repeat(" ", w.width-x)) w.Print(repeat(' ', w.width-x))
w.Move(y, x) w.Move(y, x)
} }
@ -858,7 +860,7 @@ func wrapLine(input string, prefixLength int, max int, tabstop int) []wrappedLin
width += w width += w
str := string(r) str := string(r)
if r == '\t' { if r == '\t' {
str = repeat(" ", w) str = repeat(' ', w)
} }
if prefixLength+width <= max { if prefixLength+width <= max {
line += str line += str

View File

@ -61,12 +61,8 @@ func (w *TcellWindow) Refresh() {
} }
w.lastX = 0 w.lastX = 0
w.lastY = 0 w.lastY = 0
switch w.borderStyle {
case BorderAround: w.drawBorder()
w.drawBorder(true)
case BorderHorizontal:
w.drawBorder(false)
}
} }
func (w *TcellWindow) FinishFill() { func (w *TcellWindow) FinishFill() {
@ -570,7 +566,11 @@ func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) FillReturn {
return w.fillString(str, NewColorPair(fg, bg), a) return w.fillString(str, NewColorPair(fg, bg), a)
} }
func (w *TcellWindow) drawBorder(around bool) { func (w *TcellWindow) drawBorder() {
if w.borderStyle.shape == BorderNone {
return
}
left := w.left left := w.left
right := left + w.width right := left + w.width
top := w.top top := w.top
@ -584,19 +584,19 @@ func (w *TcellWindow) drawBorder(around bool) {
} }
for x := left; x < right; x++ { for x := left; x < right; x++ {
_screen.SetContent(x, top, tcell.RuneHLine, nil, style) _screen.SetContent(x, top, w.borderStyle.horizontal, nil, style)
_screen.SetContent(x, bot-1, tcell.RuneHLine, nil, style) _screen.SetContent(x, bot-1, w.borderStyle.horizontal, nil, style)
} }
if around { if w.borderStyle.shape == BorderAround {
for y := top; y < bot; y++ { for y := top; y < bot; y++ {
_screen.SetContent(left, y, tcell.RuneVLine, nil, style) _screen.SetContent(left, y, w.borderStyle.vertical, nil, style)
_screen.SetContent(right-1, y, tcell.RuneVLine, nil, style) _screen.SetContent(right-1, y, w.borderStyle.vertical, nil, style)
} }
_screen.SetContent(left, top, tcell.RuneULCorner, nil, style) _screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
_screen.SetContent(right-1, top, tcell.RuneURCorner, nil, style) _screen.SetContent(right-1, top, w.borderStyle.topRight, nil, style)
_screen.SetContent(left, bot-1, tcell.RuneLLCorner, nil, style) _screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
_screen.SetContent(right-1, bot-1, tcell.RuneLRCorner, nil, style) _screen.SetContent(right-1, bot-1, w.borderStyle.bottomRight, nil, style)
} }
} }

View File

@ -201,14 +201,47 @@ type MouseEvent struct {
Mod bool Mod bool
} }
type BorderStyle int type BorderShape int
const ( const (
BorderNone BorderStyle = iota BorderNone BorderShape = iota
BorderAround BorderAround
BorderHorizontal BorderHorizontal
) )
type BorderStyle struct {
shape BorderShape
horizontal rune
vertical rune
topLeft rune
topRight rune
bottomLeft rune
bottomRight rune
}
func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
if unicode {
return BorderStyle{
shape: shape,
horizontal: '─',
vertical: '│',
topLeft: '┌',
topRight: '┐',
bottomLeft: '└',
bottomRight: '┘',
}
}
return BorderStyle{
shape: shape,
horizontal: '-',
vertical: '|',
topLeft: '+',
topRight: '+',
bottomLeft: '+',
bottomRight: '+',
}
}
type Renderer interface { type Renderer interface {
Init() Init()
Pause(clear bool) Pause(clear bool)