Skip to content

Commit

Permalink
Merge pull request #14 from Karmenzind/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
Karmenzind authored Jan 1, 2024
2 parents 657a4c3 + ccbdcf5 commit 940d546
Show file tree
Hide file tree
Showing 19 changed files with 670 additions and 348 deletions.
59 changes: 41 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
:stars: a crystal clear command-line dictionary, written in Go, supported Linux/Win/Mac**
:stars: a crystal clear command-line dictionary, written in Go, supported Linux/Win/Mac

**Go语言实现的简洁好用的命令行词典,跨平台、易于安装、持续维护更新**

本项目受[无道词典](https://github.com/ChestnutHeng/Wudao-dict)启发,在复刻Wudao核心功能的基础上增加了更丰富的特性。我是Wudao的多年用户,日常工作生活重度依赖随手`wd abandon`,但可惜这个项目已经很久未更新,且存在一些可以优化的地方,所以忍不住重写了一个,选择Go是为了方便地解决安装和跨平台问题。
<!-- <img src="https://raw.githubusercontent.com/Karmenzind/i/master/kd/kd_demo.gif" width="700" align="center"> -->

![](https://raw.githubusercontent.com/Karmenzind/i/master/kd/kd_demo.gif)

本项目受[无道词典](https://github.com/ChestnutHeng/Wudao-dict)启发,在复刻Wudao核心功能的基础上增加了更丰富的特性。我是Wudao的多年用户,日常工作生活重度依赖随手`wd abandon`,但可惜这个项目已经很久未更新,且存在一些可以优化的地方,所以忍不住重写了一个,选择Go是为了方便地解决安装和跨平台问题。

**TOC**
<!-- vim-markdown-toc GitLab -->

Expand All @@ -15,6 +17,8 @@
* [Windows](#windows)
* [用法](#用法)
* [配置](#配置)
* [提升体验技巧](#提升体验技巧)
* [使用tmux的悬浮窗口显示结果](#使用tmux的悬浮窗口显示结果)
* [颜色主题](#颜色主题)
* [常见问题和解决方法](#常见问题和解决方法)
* [MacOS弹出“无法打开”提醒](#macos弹出无法打开提醒)
Expand All @@ -32,14 +36,17 @@

- 单文件运行,多平台兼容,无需安装任何依赖。Windows运行截图:

![](https://raw.githubusercontent.com/Karmenzind/i/master/kd/win_terminal.png)
<img src="https://raw.githubusercontent.com/Karmenzind/i/master/kd/win_terminal.png">

- 支持查单词、词组( :eyes: 长句翻译功能也快写好了)
- 极速响应,超低延迟
- 本地词库(10W热词),可离线使用
- 支持查单词、词组,本地词库(10W+),可离线使用

> 运行时后台会自动下载数据库
- 支持`-t`翻译长句

![](https://raw.githubusercontent.com/Karmenzind/i/master/kd/longtext.png)

- 极速响应,超低延迟
- 灵活的配置项,支持修改代理、配色等
- 其他小功能:
- 多次查询相同词汇会出现提醒并加入生词本
Expand Down Expand Up @@ -84,6 +91,12 @@ sudo sh -c 'curl --create-dirs -L -o /usr/local/bin/kd https://github.com/Karmen
sudo sh -c 'curl --create-dirs -L -o /usr/local/bin/kd https://github.com/Karmenzind/kd/releases/latest/download/kd_linux_arm64 && chmod +x /usr/local/bin/kd'
```

ArchLinux可以直接通过[AUR](https://aur.archlinux.org/packages/kd)安装,例如使用yay:

```bash
yay -S aur/kd
```

<!-- ```bash -->
<!-- sudo sh -c 'curl --create-dirs -L -o /usr/local/bin/kd <URL> && chmod +x /usr/local/bin/kd' -->
<!-- ``` -->
Expand Down Expand Up @@ -147,9 +160,6 @@ paging = true
# 分页器命令,例如:less -F / bat / (不推荐) more -e
pager_command = "less -F"

# 本地最多缓存的单词条数
max_cached = 10000

# 结果中只显示英文(英译、英文例句等)
english_only = false

Expand All @@ -164,7 +174,7 @@ http_proxy = ""
clear_screen = false

# 是否开启频率提醒:本月第X次查询xxx
freq_alert = true
freq_alert = false

# (开发中)安装了emoji字体的可以输出一些emoji字符,just for fun
enable_emoji = true
Expand All @@ -180,6 +190,25 @@ enable_emoji = true
stderr = false
```

## 提升体验技巧

### 使用tmux的悬浮窗口显示结果

如果你在使用tmux,借助悬浮窗口(popup)能让查询体验更舒适友好

![](https://raw.githubusercontent.com/Karmenzind/i/master/kd/kd_tmux_popup.gif)

在bash/zsh的配置文件中加入:

```bash
if [[ -n $TMUX ]]; then
__kdwithtmuxpopup() {
tmux display-popup "kd $@"
}
alias kd=__kdwithtmuxpopup
fi
```

## 颜色主题

目前支持以下配色,后续会增加更多
Expand Down Expand Up @@ -220,22 +249,16 @@ alias kd=__kdwithpager

## 进度和计划

**进行中**

- 长句翻译
- 可更新自动提醒

**近期**

- 支持bash/zsh/fish补全,包含命令补全和[热词](https://github.com/first20hours/google-10000-english)补全
- 支持查看生词本功能
- 支持tmux浮窗模式
- 支持生词本功能

**长期**

- 增加多种主题,包含常见配色如Gruvbox/Molokai,仿照bat实现
- 支持全模块自定义显示配置
- 引入多种查询源和词库,如stardict、必应等
- 引入多种查询源和词库,如stardict、bing等
- 增加服务端
- 支持通过fzf补全
- Vim插件,浮窗显示查词结果
Expand Down
43 changes: 35 additions & 8 deletions cmd/kd.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"go.uber.org/zap"
)

var VERSION = "v0.0.3"
var VERSION = "v0.0.4"

func showPrompt() {
exename, err := pkg.GetExecutableBasename()
Expand Down Expand Up @@ -84,9 +84,9 @@ func flagStop(*cli.Context, bool) error {

func flagUpdate(ctx *cli.Context, _ bool) (err error) {
var ver string
// if pkg.GetLinuxDistro() == "arch" {
// d.EchoFine("您在使用ArchLinux,推荐通过AUR安装/升级,更方便省心")
// }
if pkg.GetLinuxDistro() == "arch" {
d.EchoFine("您在使用ArchLinux,推荐直接通过AUR安装/升级(例如`yay -S kd`),更便于维护")
}
force := ctx.Bool("force")
if force {
d.EchoRun("强制更新")
Expand Down Expand Up @@ -177,14 +177,31 @@ func flagStatus(*cli.Context, bool) error {
return nil
}

func basicCheck() {
if runtime.GOOS != "windows" {
if u, _ := user.Current(); u.Username == "root" {
d.EchoWrong("不支持Root用户")
os.Exit(1)
}
}

// XXX (k): <2024-01-01>
// if exename, err := pkg.GetExecutableBasename(); err == nil {
// if exename != "kd" {
// d.EchoWrong("请将名字改成kd")
// os.Exit(1)
// }
// } else {
// d.EchoError(err.Error())
// }
}

func main() {
basicCheck()
config.InitConfig()
cfg := config.Cfg
d.ApplyConfig(cfg.EnableEmoji)
if u, _ := user.Current(); u.Username == "root" {
d.EchoWrong("不支持Root用户")
os.Exit(1)
}

if cfg.Logging.Enable {
l, err := logger.InitLogger(&cfg.Logging)
if err != nil {
Expand Down Expand Up @@ -292,4 +309,14 @@ func main() {
zap.S().Errorf("APP stopped: %s", err)
d.EchoError(err.Error())
}

if ltag := update.GetCachedLatestTag(); ltag != "" {
if update.CompareVersions(ltag, VERSION) == 1 {
prompt := fmt.Sprintf("发现新版本%s,请执行`kd --update`更新", ltag)
if pkg.GetLinuxDistro() == "arch" {
prompt+= "。ArchLinux推荐通过AUR安装/升级"
}
d.EchoWeakNotice(prompt)
}
}
}
4 changes: 2 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ type Config struct {
Paging bool `default:"true" toml:"paging"`
PagerCommand string `toml:"pager_command"`
AutoClear bool `default:"false" toml:"auto_clear"`
MaxCached uint `default:"10000" toml:"max_cached"`
// MaxCached uint `default:"10000" toml:"max_cached"`
EnglishOnly bool `default:"false" toml:"english_only"`
Theme string `default:"temp" toml:"theme"`
HTTPProxy string `toml:"http_proxy"`
ClearScreen bool `toml:"clear_screen" default:"false"`
FreqAlert bool `toml:"freq_alert" default:"true"`
FreqAlert bool `toml:"freq_alert" default:"false"`

Logging LoggerConfig `toml:"logging"`

Expand Down
6 changes: 5 additions & 1 deletion internal/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func GetCachedQuery(r *model.Result) (err error) {
}
c.Close()
j := jb.Bytes()
zap.S().Debugf("Got cached json %s", j)

if len(j) > 0 {
err = json.Unmarshal(j, r)
Expand All @@ -50,10 +51,13 @@ func UpdateQueryCache(r *model.Result) (err error) {
if !r.Found {
return
}

j, err := json.Marshal(r)
if err != nil {
zap.S().Warnf("Failed to marshal %+v: %s", r, err)
return
}
zap.S().Debugf("Got marshalled json to save: %s", j)

var zb bytes.Buffer
jw := zlib.NewWriter(&zb)
Expand All @@ -66,7 +70,7 @@ func UpdateQueryCache(r *model.Result) (err error) {
if err != nil {
zap.S().Errorf("Failed to update cache for '%s'. Error: %s", r.Query, err)
}
zap.S().Debugf("Updated cache for '%s'. len: %d", r.Query, len(detail))
zap.S().Debugf("Updated cache for '%s'. len: %d", r.Query, len(detail))
return
}

Expand Down
78 changes: 44 additions & 34 deletions internal/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,32 @@ import (
"github.com/Karmenzind/kd/internal/model"
q "github.com/Karmenzind/kd/internal/query"
d "github.com/Karmenzind/kd/pkg/decorate"
"github.com/Karmenzind/kd/pkg/str"
"go.uber.org/zap"
)

func ensureDaemon(running chan bool) {
if !daemon.ServerIsRunning() {
err := daemon.StartDaemonProcess()
if err != nil {
d.EchoRun("未找到守护进程,正在启动...")
d.EchoRun("未找到守护进程,正在启动...")
d.EchoFatal(err.Error())
}
running <- true
}
running <- true
running <- true
}

func Query(query string, noCache bool, longText bool) (r *model.Result, err error) {
query = strings.ToLower(strings.Trim(query, " "))
// TODO (k): <2024-01-02> regexp
query = str.Simplify(query)
if !longText {
query = strings.ToLower(query)
}
// query = strings.ToLower(strings.Trim(query, " "))
// query = strings.ReplaceAll(query, "\n", " ")

r = &model.Result{Query: query, IsLongText: longText}
r = buildResult(query, longText)
r.History = make(chan int, 1)

daemonRunning := make(chan bool)
Expand All @@ -53,43 +60,46 @@ func Query(query string, noCache bool, longText bool) (r *model.Result, err erro
return
}

// if longText {
// r.Found = false
// r.Prompt = "暂不支持长句翻译"
// return
// }

if longText {
r.Found = false
r.Prompt = "暂不支持长句翻译"
return
}

var inNotFound bool
line, err := cache.CheckNotFound(r.Query)
if err != nil {
zap.S().Warnf("[cache] check not found error: %s", err)
} else if line > 0 {
if !noCache {
r.Found = false
zap.S().Debugf("`%s` is in not-found-list", r.Query)
return
}
inNotFound = true
}
r.Initialize()

if !noCache {
cacheErr := q.FetchCached(r)
if cacheErr != nil {
zap.S().Warnf("[cache] Query error: %s", cacheErr)
var inNotFound bool
var line int
if !longText {
line, err = cache.CheckNotFound(r.Query)
if err != nil {
zap.S().Warnf("[cache] check not found error: %s", err)
} else if line > 0 {
if !noCache {
r.Found = false
zap.S().Debugf("`%s` is in not-found-list", r.Query)
return
}
inNotFound = true
}
if r.Found {
return
r.Initialize()

if !noCache {
cacheErr := q.FetchCached(r)
if cacheErr != nil {
zap.S().Warnf("[cache] Query error: %s", cacheErr)
}
if r.Found {
return
}
_ = err
}
_ = err

}

if <-daemonRunning {
err = QueryDaemon(r)
if err == nil && r.Found && inNotFound {
go cache.RemoveNotFound(r.Query)
}
if err == nil && r.Found && inNotFound {
go cache.RemoveNotFound(r.Query)
}
} else {
d.EchoFatal("守护进程未启动,请手动执行`kd --daemon`")
}
Expand Down
18 changes: 15 additions & 3 deletions internal/daemon/cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/Karmenzind/kd/internal/cache"
"github.com/Karmenzind/kd/internal/update"
"github.com/Karmenzind/kd/pkg"
_ "github.com/mattn/go-sqlite3"
"go.uber.org/zap"
Expand Down Expand Up @@ -41,10 +42,21 @@ func cronDeleteSpam() {
}

func cronCheckUpdate() {
ticker := time.NewTicker(120 * time.Second)
ticker := time.NewTicker(3600 * 12 * time.Second)
for {
t := <-ticker.C
zap.S().Debugf("Tick at %s", t)
// TODO (k): <2024-01-01> 改成检查文件Stat来判断时长
<-ticker.C

for i := 0; i < 3; i++ {
tag, err := update.GetLatestTag()
if err == nil {
fmt.Println("最新Tag", tag)
break
}
zap.S().Warnf("Failed to get latest tag: %s", err)
time.Sleep(5 * time.Second)
}

}
}

Expand Down
Loading

0 comments on commit 940d546

Please sign in to comment.