Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I change view.go and edit.go to support CJK font #173

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

Minimalist Go package aimed at creating Console User Interfaces.

## 关于本fork的说明(About this fork)

Add CJK support, both edit.go and view.go.
修正了中文显示功能,为此我修改了`edit.go`和`view.go`。
因为该补丁还没有被原作者采用,使用时需要用用本代码覆盖 `github.com/jroimartin/gocui` 的代码。
2018-8-31 增加 `(* view)ReadEditor()`,能够正确过滤输入的中文,删除自动添加的占位符。

## Features

* Minimalist API.
Expand Down
138 changes: 138 additions & 0 deletions _examples/cjkedit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//Try cjk patch of rocket049. example of view.ReadEditor
package main

import (
"fmt"
"log"

"github.com/jroimartin/gocui"
)

func viewOutput(g *gocui.Gui, x0, y0, x1, y1 int) error {
v, err := g.SetView("out", x0, y0, x1, y1)
if err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Wrap = true
v.Overwrite = false
v.Autoscroll = true
v.SelBgColor = gocui.ColorRed
v.Title = "Messages"
}
return nil
}
func viewInput(g *gocui.Gui, x0, y0, x1, y1 int) error {
if v, err := g.SetView("main", x0, y0, x1, y1); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.Editable = true
v.Wrap = true
v.Overwrite = false
if _, err := g.SetCurrentView("main"); err != nil {
return err
}
fmt.Fprintf(v, "example,中文输入示例,按回车输入。press ENTER to input")
}
return nil
}

func layout(g *gocui.Gui) error {
maxX, maxY := g.Size()
if err := viewOutput(g, 1, 1, maxX-1, maxY-4); err != nil {
return err
}
if err := viewInput(g, 1, maxY-3, maxX-1, maxY-1); err != nil {
return err
}
return nil
}

var pos int

func pasteUP(g *gocui.Gui, cv *gocui.View) error {
v, err := g.View("out")
if err != nil {
fmt.Fprintf(cv, "error:%s", err)
return nil
}
bls := v.BufferLines()
lnum := len(bls)
if pos < lnum-1 {
pos++
}
cv.Clear()
fmt.Fprintf(cv, "%s", bls[lnum-pos-1])
return nil
}

func pasteDown(g *gocui.Gui, cv *gocui.View) error {
v, err := g.View("out")
if err != nil {
fmt.Fprintf(cv, "error:%s", err)
return nil
}
if pos > 0 {
pos--
}
bls := v.BufferLines()
lnum := len(bls)
cv.Clear()
fmt.Fprintf(cv, "%s", bls[lnum-pos-1])
return nil
}

func quit(g *gocui.Gui, v *gocui.View) error {
return gocui.ErrQuit
}

func main() {
g, err := gocui.NewGui(gocui.OutputNormal)
if err != nil {
//log.Panicln(err)
}

g.Cursor = true
g.Mouse = false
g.ASCII = false

g.SetManagerFunc(layout)
//layout(g)

if err := g.SetKeybinding("main", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil {
log.Panicln(err)
}

if err := g.SetKeybinding("main", gocui.KeyEnter, gocui.ModNone, updateInput); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("main", gocui.KeyArrowDown, gocui.ModNone, pasteDown); err != nil {
log.Panicln(err)
}
if err := g.SetKeybinding("main", gocui.KeyArrowUp, gocui.ModNone, pasteUP); err != nil {
log.Panicln(err)
}

if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}

g.Close()
}

func updateInput(g *gocui.Gui, cv *gocui.View) error {
v, err := g.View("out")
if cv != nil && err == nil {
var p = cv.ReadEditor()
if p != nil {
v.Write([]byte("你:"))
v.Write(append(p, '\n'))
}
v.Autoscroll = true
}
l := len(cv.Buffer())
cv.MoveCursor(0-l, 0, true)
cv.Clear()
return nil
}
40 changes: 40 additions & 0 deletions cjkeditor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//Help editor to Input cjk language.
//Author [email protected]
package gocui

import (
"bytes"

"github.com/mattn/go-runewidth"
)

func modifyCJK(p []byte) []byte {
buf := bytes.NewBuffer(bytes.Trim(p, " \n\t"))
sz := len(buf.String())
buf1 := bytes.NewBufferString("")
var r rune
var wr bool
for i := 0; i < sz; i++ {
r, _, _ = buf.ReadRune()
if r != rune(0) && wr == false {
buf1.WriteRune(r)
} else if wr == true {
if r != rune(' ') {
buf1.WriteRune(r)
}
}
wr = runewidth.RuneWidth(r) > 1
}
return buf1.Bytes()
}

//ReadEditor Read byte array from editor 'v', delete the auto appended blank after CJK runes.
func (v *View) ReadEditor() []byte {
var b = make([]byte, 300)
n, _ := v.Read(b)
if n > 0 {
return modifyCJK(b[:n])
} else {
return nil
}
}
27 changes: 16 additions & 11 deletions edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@

package gocui

import "errors"
import (
"errors"

"github.com/mattn/go-runewidth"
)

const maxInt = int(^uint(0) >> 1)

Expand Down Expand Up @@ -55,7 +59,7 @@ func simpleEditor(v *View, key Key, ch rune, mod Modifier) {
// EditWrite writes a rune at the cursor position.
func (v *View) EditWrite(ch rune) {
v.writeRune(v.cx, v.cy, ch)
v.MoveCursor(1, 0, true)
v.MoveCursor(runewidth.RuneWidth(ch), 0, true)
}

// EditDelete deletes a rune at the cursor position. back determines the
Expand Down Expand Up @@ -89,12 +93,12 @@ func (v *View) EditDelete(back bool) {
v.MoveCursor(-1, 0, true)
}
} else { // wrapped line
v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
v.MoveCursor(-1, 0, true)
ch, _ := v.deleteRune(len(v.viewLines[y-1].line)-1, v.cy-1)
v.MoveCursor(0-runewidth.RuneWidth(ch), 0, true)
}
} else { // middle/end of the line
v.deleteRune(v.cx-1, v.cy)
v.MoveCursor(-1, 0, true)
ch, _ := v.deleteRune(v.cx-1, v.cy)
v.MoveCursor(0-runewidth.RuneWidth(ch), 0, true)
}
} else {
if x == len(v.viewLines[y].line) { // end of the line
Expand Down Expand Up @@ -275,19 +279,20 @@ func (v *View) writeRune(x, y int, ch rune) error {

// deleteRune removes a rune from the view's internal buffer, at the
// position corresponding to the point (x, y).
func (v *View) deleteRune(x, y int) error {
func (v *View) deleteRune(x, y int) (ch rune, err error) {
v.tainted = true

x, y, err := v.realPosition(x, y)
x, y, err = v.realPosition(x, y)
if err != nil {
return err
return 0, err
}

if x < 0 || y < 0 || y >= len(v.lines) || x >= len(v.lines[y]) {
return errors.New("invalid point")
return 0, errors.New("invalid point")
}
chx := v.lines[y][x]
v.lines[y] = append(v.lines[y][:x], v.lines[y][x+1:]...)
return nil
return chx.chr, nil
}

// mergeLines merges the lines "y" and "y+1" if possible.
Expand Down
3 changes: 2 additions & 1 deletion view.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io"
"strings"

"github.com/mattn/go-runewidth"
"github.com/nsf/termbox-go"
)

Expand Down Expand Up @@ -353,7 +354,7 @@ func (v *View) draw() error {
if err := v.setRune(x, y, c.chr, fgColor, bgColor); err != nil {
return err
}
x++
x += runewidth.RuneWidth(c.chr)
}
y++
}
Expand Down