Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
HugeYuan
delve
提交
8e91d3b0
D
delve
项目概览
HugeYuan
/
delve
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
delve
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
8e91d3b0
编写于
1月 28, 2021
作者:
A
Alessandro Arzilli
提交者:
GitHub
1月 28, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
terminal: Go syntax highlighting for listings (#2294)
Fixes #1273
上级
c40774d3
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
373 addition
and
71 deletion
+373
-71
pkg/config/config.go
pkg/config/config.go
+26
-2
pkg/terminal/colorize/colorize.go
pkg/terminal/colorize/colorize.go
+298
-0
pkg/terminal/command.go
pkg/terminal/command.go
+10
-33
pkg/terminal/terminal.go
pkg/terminal/terminal.go
+39
-36
未找到文件。
pkg/config/config.go
浏览文件 @
8e91d3b0
...
...
@@ -54,8 +54,24 @@ type Config struct {
ShowLocationExpr
bool
`yaml:"show-location-expr"`
// Source list line-number color (3/4 bit color codes as defined
// here: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors)
SourceListLineColor
int
`yaml:"source-list-line-color"`
// here: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors),
// or a string containing a terminal escape sequence.
SourceListLineColor
interface
{}
`yaml:"source-list-line-color"`
// Source list arrow color, as a terminal escape sequence.
SourceListArrowColor
string
`yaml:"source-list-arrow-color"`
// Source list keyword color, as a terminal escape sequence.
SourceListKeywordColor
string
`yaml:"source-list-keyword-color"`
// Source list string color, as a terminal escape sequence.
SourceListStringColor
string
`yaml:"source-list-string-color"`
// Source list number color, as a terminal escape sequence.
SourceListNumberColor
string
`yaml:"source-list-number-color"`
// Source list comment color, as a terminal escape sequence.
SourceListCommentColor
string
`yaml:"source-list-comment-color"`
// number of lines to list above and below cursor when printfile() is
// called (i.e. when execution stops, listCommand is used, etc)
...
...
@@ -215,8 +231,16 @@ func writeDefaultConfig(f *os.File) error {
# Uncomment the following line and set your preferred ANSI foreground color
# for source line numbers in the (list) command (if unset, default is 34,
# dark blue) See https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit
# Alternatively a string containing an escape sequence can also be used.
# source-list-line-color: 34
# Uncomment the following lines to change the colors used by syntax highlighting.
# source-list-keyword-color: "\x1b[0m"
# source-list-string-color: "\x1b[92m"
# source-list-number-color: "\x1b[0m"
# source-list-comment-color: "\x1b[95m"
# source-list-arrow-color: "\x1b[93m"
# Uncomment to change the number of lines printed above and below cursor when
# listing source code.
# source-list-line-count: 5
...
...
pkg/terminal/colorize/colorize.go
0 → 100644
浏览文件 @
8e91d3b0
package
colorize
import
(
"fmt"
"go/ast"
"go/parser"
"go/token"
"io"
"io/ioutil"
"path/filepath"
"reflect"
"sort"
)
// Style describes the style of a chunk of text.
type
Style
uint8
const
(
NormalStyle
Style
=
iota
KeywordStyle
StringStyle
NumberStyle
CommentStyle
LineNoStyle
ArrowStyle
)
// Print prints to out a syntax highlighted version of the text read from
// reader, between lines startLine and endLine.
func
Print
(
out
io
.
Writer
,
path
string
,
reader
io
.
Reader
,
startLine
,
endLine
,
arrowLine
int
,
colorEscapes
map
[
Style
]
string
)
error
{
buf
,
err
:=
ioutil
.
ReadAll
(
reader
)
if
err
!=
nil
{
return
err
}
w
:=
&
lineWriter
{
w
:
out
,
lineRange
:
[
2
]
int
{
startLine
,
endLine
},
arrowLine
:
arrowLine
,
colorEscapes
:
colorEscapes
}
if
filepath
.
Ext
(
path
)
!=
".go"
{
w
.
Write
(
NormalStyle
,
buf
,
true
)
return
nil
}
var
fset
token
.
FileSet
f
,
err
:=
parser
.
ParseFile
(
&
fset
,
path
,
buf
,
parser
.
ParseComments
)
if
err
!=
nil
{
w
.
Write
(
NormalStyle
,
buf
,
true
)
return
nil
}
var
base
int
fset
.
Iterate
(
func
(
file
*
token
.
File
)
bool
{
base
=
file
.
Base
()
return
false
})
toks
:=
[]
colorTok
{}
emit
:=
func
(
tok
token
.
Token
,
start
,
end
token
.
Pos
)
{
if
_
,
ok
:=
tokenToStyle
[
tok
];
!
ok
{
return
}
start
-=
token
.
Pos
(
base
)
if
end
==
token
.
NoPos
{
// end == token.NoPos it's a keyword and we have to find where it ends by looking at the file
for
end
=
start
;
end
<
token
.
Pos
(
len
(
buf
));
end
++
{
if
buf
[
end
]
<
'a'
||
buf
[
end
]
>
'z'
{
break
}
}
}
else
{
end
-=
token
.
Pos
(
base
)
}
if
start
<
0
||
start
>=
end
||
end
>
token
.
Pos
(
len
(
buf
))
{
// invalid token?
return
}
toks
=
append
(
toks
,
colorTok
{
tok
,
int
(
start
),
int
(
end
)})
}
emit
(
token
.
PACKAGE
,
f
.
Package
,
token
.
NoPos
)
for
_
,
cgrp
:=
range
f
.
Comments
{
for
_
,
cmnt
:=
range
cgrp
.
List
{
emit
(
token
.
COMMENT
,
cmnt
.
Pos
(),
cmnt
.
End
())
}
}
ast
.
Inspect
(
f
,
func
(
n
ast
.
Node
)
bool
{
if
n
==
nil
{
return
true
}
switch
n
:=
n
.
(
type
)
{
case
*
ast
.
BasicLit
:
emit
(
n
.
Kind
,
n
.
Pos
(),
n
.
End
())
return
true
case
*
ast
.
Ident
:
//TODO(aarzilli): builtin functions? basic types?
return
true
case
*
ast
.
IfStmt
:
emit
(
token
.
IF
,
n
.
If
,
token
.
NoPos
)
if
n
.
Else
!=
nil
{
for
elsepos
:=
int
(
n
.
Body
.
End
())
-
base
;
elsepos
<
len
(
buf
)
-
4
;
elsepos
++
{
if
string
(
buf
[
elsepos
:
][
:
4
])
==
"else"
{
emit
(
token
.
ELSE
,
token
.
Pos
(
elsepos
+
base
),
token
.
Pos
(
elsepos
+
base
+
4
))
break
}
}
}
return
true
}
nval
:=
reflect
.
ValueOf
(
n
)
if
nval
.
Kind
()
!=
reflect
.
Ptr
{
return
true
}
nval
=
nval
.
Elem
()
if
nval
.
Kind
()
!=
reflect
.
Struct
{
return
true
}
tokposval
:=
nval
.
FieldByName
(
"TokPos"
)
tokval
:=
nval
.
FieldByName
(
"Tok"
)
if
tokposval
!=
(
reflect
.
Value
{})
&&
tokval
!=
(
reflect
.
Value
{})
{
emit
(
tokval
.
Interface
()
.
(
token
.
Token
),
tokposval
.
Interface
()
.
(
token
.
Pos
),
token
.
NoPos
)
}
for
_
,
kwname
:=
range
[]
string
{
"Case"
,
"Begin"
,
"Defer"
,
"Pacakge"
,
"For"
,
"Func"
,
"Go"
,
"Interface"
,
"Map"
,
"Return"
,
"Select"
,
"Struct"
,
"Switch"
}
{
kwposval
:=
nval
.
FieldByName
(
kwname
)
if
kwposval
!=
(
reflect
.
Value
{})
{
kwpos
,
ok
:=
kwposval
.
Interface
()
.
(
token
.
Pos
)
if
ok
{
emit
(
token
.
ILLEGAL
,
kwpos
,
token
.
NoPos
)
}
}
}
return
true
})
sort
.
Slice
(
toks
,
func
(
i
,
j
int
)
bool
{
return
toks
[
i
]
.
start
<
toks
[
j
]
.
start
})
flush
:=
func
(
start
,
end
int
,
style
Style
)
{
if
start
<
end
{
w
.
Write
(
style
,
buf
[
start
:
end
],
end
==
len
(
buf
))
}
}
cur
:=
0
for
_
,
tok
:=
range
toks
{
flush
(
cur
,
tok
.
start
,
NormalStyle
)
flush
(
tok
.
start
,
tok
.
end
,
tokenToStyle
[
tok
.
tok
])
cur
=
tok
.
end
}
if
cur
!=
len
(
buf
)
{
flush
(
cur
,
len
(
buf
),
NormalStyle
)
}
return
nil
}
var
tokenToStyle
=
map
[
token
.
Token
]
Style
{
token
.
ILLEGAL
:
KeywordStyle
,
token
.
COMMENT
:
CommentStyle
,
token
.
INT
:
NumberStyle
,
token
.
FLOAT
:
NumberStyle
,
token
.
IMAG
:
NumberStyle
,
token
.
CHAR
:
StringStyle
,
token
.
STRING
:
StringStyle
,
token
.
BREAK
:
KeywordStyle
,
token
.
CASE
:
KeywordStyle
,
token
.
CHAN
:
KeywordStyle
,
token
.
CONST
:
KeywordStyle
,
token
.
CONTINUE
:
KeywordStyle
,
token
.
DEFAULT
:
KeywordStyle
,
token
.
DEFER
:
KeywordStyle
,
token
.
ELSE
:
KeywordStyle
,
token
.
FALLTHROUGH
:
KeywordStyle
,
token
.
FOR
:
KeywordStyle
,
token
.
FUNC
:
KeywordStyle
,
token
.
GO
:
KeywordStyle
,
token
.
GOTO
:
KeywordStyle
,
token
.
IF
:
KeywordStyle
,
token
.
IMPORT
:
KeywordStyle
,
token
.
INTERFACE
:
KeywordStyle
,
token
.
MAP
:
KeywordStyle
,
token
.
PACKAGE
:
KeywordStyle
,
token
.
RANGE
:
KeywordStyle
,
token
.
RETURN
:
KeywordStyle
,
token
.
SELECT
:
KeywordStyle
,
token
.
STRUCT
:
KeywordStyle
,
token
.
SWITCH
:
KeywordStyle
,
token
.
TYPE
:
KeywordStyle
,
token
.
VAR
:
KeywordStyle
,
}
type
colorTok
struct
{
tok
token
.
Token
// the token type or ILLEGAL for keywords
start
,
end
int
// start and end positions of the token
}
type
lineWriter
struct
{
w
io
.
Writer
lineRange
[
2
]
int
arrowLine
int
curStyle
Style
started
bool
lineno
int
colorEscapes
map
[
Style
]
string
}
func
(
w
*
lineWriter
)
style
(
style
Style
)
{
if
w
.
colorEscapes
==
nil
{
return
}
esc
:=
w
.
colorEscapes
[
style
]
if
esc
==
""
{
esc
=
w
.
colorEscapes
[
NormalStyle
]
}
fmt
.
Fprintf
(
w
.
w
,
"%s"
,
esc
)
}
func
(
w
*
lineWriter
)
inrange
()
bool
{
lno
:=
w
.
lineno
if
!
w
.
started
{
lno
=
w
.
lineno
+
1
}
return
lno
>=
w
.
lineRange
[
0
]
&&
lno
<
w
.
lineRange
[
1
]
}
func
(
w
*
lineWriter
)
nl
()
{
w
.
lineno
++
if
!
w
.
inrange
()
||
!
w
.
started
{
return
}
w
.
style
(
ArrowStyle
)
if
w
.
lineno
==
w
.
arrowLine
{
fmt
.
Fprintf
(
w
.
w
,
"=>"
)
}
else
{
fmt
.
Fprintf
(
w
.
w
,
" "
)
}
w
.
style
(
LineNoStyle
)
fmt
.
Fprintf
(
w
.
w
,
"%4d:
\t
"
,
w
.
lineno
)
w
.
style
(
w
.
curStyle
)
}
func
(
w
*
lineWriter
)
writeInternal
(
style
Style
,
data
[]
byte
)
{
if
!
w
.
inrange
()
{
return
}
if
!
w
.
started
{
w
.
started
=
true
w
.
curStyle
=
style
w
.
nl
()
}
else
if
w
.
curStyle
!=
style
{
w
.
curStyle
=
style
w
.
style
(
w
.
curStyle
)
}
w
.
w
.
Write
(
data
)
}
func
(
w
*
lineWriter
)
Write
(
style
Style
,
data
[]
byte
,
last
bool
)
{
cur
:=
0
for
i
:=
range
data
{
if
data
[
i
]
==
'\n'
{
if
last
&&
i
==
len
(
data
)
-
1
{
w
.
writeInternal
(
style
,
data
[
cur
:
i
])
if
w
.
curStyle
!=
NormalStyle
{
w
.
style
(
NormalStyle
)
}
if
w
.
inrange
()
{
w
.
w
.
Write
([]
byte
{
'\n'
})
}
last
=
false
}
else
{
w
.
writeInternal
(
style
,
data
[
cur
:
i
+
1
])
w
.
nl
()
}
cur
=
i
+
1
}
}
if
cur
<
len
(
data
)
{
w
.
writeInternal
(
style
,
data
[
cur
:
])
}
if
last
{
if
w
.
curStyle
!=
NormalStyle
{
w
.
style
(
NormalStyle
)
}
if
w
.
inrange
()
{
w
.
w
.
Write
([]
byte
{
'\n'
})
}
}
}
pkg/terminal/command.go
浏览文件 @
8e91d3b0
...
...
@@ -24,6 +24,7 @@ import (
"github.com/cosiner/argv"
"github.com/go-delve/delve/pkg/locspec"
"github.com/go-delve/delve/pkg/terminal/colorize"
"github.com/go-delve/delve/service"
"github.com/go-delve/delve/service/api"
"github.com/go-delve/delve/service/rpc2"
...
...
@@ -2247,7 +2248,7 @@ func printcontext(t *Term, state *api.DebuggerState) {
if
th
.
File
==
""
{
fmt
.
Printf
(
"Stopped at: 0x%x
\n
"
,
state
.
CurrentThread
.
PC
)
t
.
Println
(
"=>"
,
"no source available"
)
_
=
colorize
.
Print
(
t
.
stdout
,
""
,
bytes
.
NewReader
([]
byte
(
"no source available"
)),
1
,
10
,
1
,
nil
)
return
}
...
...
@@ -2424,6 +2425,13 @@ func printfile(t *Term, filename string, line int, showArrow bool) error {
if
filename
==
""
{
return
nil
}
lineCount
:=
t
.
conf
.
GetSourceListLineCount
()
arrowLine
:=
0
if
showArrow
{
arrowLine
=
line
}
file
,
err
:=
os
.
Open
(
t
.
substitutePath
(
filename
))
if
err
!=
nil
{
return
err
...
...
@@ -2436,38 +2444,7 @@ func printfile(t *Term, filename string, line int, showArrow bool) error {
fmt
.
Println
(
"Warning: listing may not match stale executable"
)
}
lineCount
:=
t
.
conf
.
GetSourceListLineCount
()
buf
:=
bufio
.
NewScanner
(
file
)
l
:=
line
for
i
:=
1
;
i
<
l
-
lineCount
;
i
++
{
if
!
buf
.
Scan
()
{
return
nil
}
}
s
:=
l
-
lineCount
if
s
<
1
{
s
=
1
}
for
i
:=
s
;
i
<=
l
+
lineCount
;
i
++
{
if
!
buf
.
Scan
()
{
return
nil
}
var
prefix
string
if
showArrow
{
prefix
=
" "
if
i
==
l
{
prefix
=
"=>"
}
}
prefix
=
fmt
.
Sprintf
(
"%s%4d:
\t
"
,
prefix
,
i
)
t
.
Println
(
prefix
,
buf
.
Text
())
}
return
nil
return
colorize
.
Print
(
t
.
stdout
,
file
.
Name
(),
file
,
line
-
lineCount
,
line
+
lineCount
+
1
,
arrowLine
,
t
.
colorEscapes
)
}
// ExitRequestError is returned when the user
...
...
pkg/terminal/terminal.go
浏览文件 @
8e91d3b0
...
...
@@ -14,6 +14,7 @@ import (
"github.com/go-delve/delve/pkg/config"
"github.com/go-delve/delve/pkg/locspec"
"github.com/go-delve/delve/pkg/terminal/colorize"
"github.com/go-delve/delve/pkg/terminal/starbind"
"github.com/go-delve/delve/service"
"github.com/go-delve/delve/service/api"
...
...
@@ -46,15 +47,15 @@ const (
// Term represents the terminal running dlv.
type
Term
struct
{
client
service
.
Client
conf
*
config
.
Config
prompt
string
line
*
liner
.
State
cmds
*
Commands
dumb
bool
stdout
io
.
Writer
InitFile
string
displays
[
]
string
client
service
.
Client
conf
*
config
.
Config
prompt
string
line
*
liner
.
State
cmds
*
Commands
stdout
io
.
Writer
InitFile
string
displays
[]
string
colorEscapes
map
[
colorize
.
Style
]
string
historyFile
*
os
.
File
...
...
@@ -84,30 +85,41 @@ func New(client service.Client, conf *config.Config) *Term {
conf
=
&
config
.
Config
{}
}
var
w
io
.
Writer
dumb
:=
strings
.
ToLower
(
os
.
Getenv
(
"TERM"
))
==
"dumb"
if
dumb
{
w
=
os
.
Stdout
}
else
{
w
=
getColorableWriter
()
}
if
(
conf
.
SourceListLineColor
>
ansiWhite
&&
conf
.
SourceListLineColor
<
ansiBrBlack
)
||
conf
.
SourceListLineColor
<
ansiBlack
||
conf
.
SourceListLineColor
>
ansiBrWhite
{
conf
.
SourceListLineColor
=
ansiBlue
}
t
:=
&
Term
{
client
:
client
,
conf
:
conf
,
prompt
:
"(dlv) "
,
line
:
liner
.
NewLiner
(),
cmds
:
cmds
,
dumb
:
dumb
,
stdout
:
w
,
stdout
:
os
.
Stdout
,
}
if
strings
.
ToLower
(
os
.
Getenv
(
"TERM"
))
!=
"dumb"
{
t
.
stdout
=
getColorableWriter
()
t
.
colorEscapes
=
make
(
map
[
colorize
.
Style
]
string
)
t
.
colorEscapes
[
colorize
.
NormalStyle
]
=
terminalResetEscapeCode
wd
:=
func
(
s
string
,
defaultCode
int
)
string
{
if
s
==
""
{
return
fmt
.
Sprintf
(
terminalHighlightEscapeCode
,
defaultCode
)
}
return
s
}
t
.
colorEscapes
[
colorize
.
KeywordStyle
]
=
conf
.
SourceListKeywordColor
t
.
colorEscapes
[
colorize
.
StringStyle
]
=
wd
(
conf
.
SourceListStringColor
,
ansiBrGreen
)
t
.
colorEscapes
[
colorize
.
NumberStyle
]
=
conf
.
SourceListNumberColor
t
.
colorEscapes
[
colorize
.
CommentStyle
]
=
wd
(
conf
.
SourceListCommentColor
,
ansiBrMagenta
)
t
.
colorEscapes
[
colorize
.
ArrowStyle
]
=
wd
(
conf
.
SourceListArrowColor
,
ansiBrYellow
)
switch
x
:=
conf
.
SourceListLineColor
.
(
type
)
{
case
string
:
t
.
colorEscapes
[
colorize
.
LineNoStyle
]
=
x
case
int
:
if
(
x
>
ansiWhite
&&
x
<
ansiBrBlack
)
||
x
<
ansiBlack
||
x
>
ansiBrWhite
{
x
=
ansiBlue
}
t
.
colorEscapes
[
colorize
.
LineNoStyle
]
=
fmt
.
Sprintf
(
terminalHighlightEscapeCode
,
x
)
case
nil
:
t
.
colorEscapes
[
colorize
.
LineNoStyle
]
=
fmt
.
Sprintf
(
terminalHighlightEscapeCode
,
ansiBlue
)
}
}
if
client
!=
nil
{
...
...
@@ -273,15 +285,6 @@ func (t *Term) Run() (int, error) {
}
}
// Println prints a line to the terminal.
func
(
t
*
Term
)
Println
(
prefix
,
str
string
)
{
if
!
t
.
dumb
{
terminalColorEscapeCode
:=
fmt
.
Sprintf
(
terminalHighlightEscapeCode
,
t
.
conf
.
SourceListLineColor
)
prefix
=
fmt
.
Sprintf
(
"%s%s%s"
,
terminalColorEscapeCode
,
prefix
,
terminalResetEscapeCode
)
}
fmt
.
Fprintf
(
t
.
stdout
,
"%s%s
\n
"
,
prefix
,
str
)
}
// Substitutes directory to source file.
//
// Ensures that only directory is substituted, for example:
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录