├── .DS_Store
├── .gitignore
├── LICENSE
├── README.md
├── app.go
├── build
├── .DS_Store
├── README.md
├── appicon.png
├── darwin
│ └── Info.plist
└── windows
│ ├── code-counter.exe.manifest
│ ├── icon.ico
│ ├── info.json
│ ├── installer
│ ├── project.nsi
│ └── wails_tools.nsh
│ └── wails.exe.manifest
├── count
├── countCode.go
├── countFile.go
├── countFile_test.go
├── defaultConfig.go
├── readDir.go
└── utils.go
├── frontend
├── .DS_Store
├── dist
│ └── .gitkeep
├── index.html
├── package-lock.json
├── package.json
├── public
│ └── .gitkeep
├── src
│ ├── .DS_Store
│ ├── App.vue
│ ├── assets
│ │ ├── github.png
│ │ └── logo.png
│ ├── components
│ │ ├── CItem.vue
│ │ └── CModal.vue
│ ├── main.js
│ ├── router
│ │ └── index.js
│ ├── views
│ │ ├── AddFile.vue
│ │ ├── Home.vue
│ │ └── ShowResult.vue
│ └── wailsjs
│ │ ├── go
│ │ └── models.ts
│ │ └── runtime
│ │ ├── package.json
│ │ ├── runtime.d.ts
│ │ └── runtime.js
└── vite.config.js
├── go.mod
├── go.sum
├── main.go
├── screenshot
├── .DS_Store
├── screenshot1.png
├── screenshot2.png
└── screenshot3.png
├── scripts
├── build-macos-arm.sh
├── build-macos-intel.sh
├── build-macos.sh
├── build-windows.sh
├── build.sh
└── install-wails-cli.sh
└── wails.json
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Wails bin directory
2 | build/bin
3 |
4 | # IDEs
5 | .idea
6 | .vscode
7 | .DS_Store
8 |
9 | # fronted resources
10 | frontend/node_modules
11 | frontend/src/wailsjs
12 | frontend/dist/index.html
13 | frontend/dist/assets
14 | frontend/package.json.md5
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Alan Chen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Code Counter
2 |
3 | > An application to count code in wails(golang)
4 |
5 | > version: 2.0.1
6 |
7 | > Author: Alan Chen
8 |
9 | > Technology stack: Vue2 + Vite + iview + Golang + Wails v2
10 |
11 | `electron版本见branch v1`
12 |
13 | ### Features
14 | * 采用wails v2包生成app、exe可执行文件,方便离线使用。
15 | * wails使用系统自带webview,而不是electron内置,软件打包后安装包2~3M,比内置chromium方案磁盘占用、内存占用率优秀很多
16 | * golang的go routine在读取文件和cpu计算会充分利用多核处理器,处理速度更快
17 | * 支持文件夹读取文件,自定义统计哪个文件夹下代码数量
18 | * 支持文件(夹)过滤,支持对应后缀名文件过滤
19 | * 支持对应后缀名文件添加自定义注释规则,目前只自带很小一部分代码的默认注释规则
20 |
21 | 
22 | 
23 | 
24 |
25 | ### Usage Help
26 | 1. 点击即可读取文件夹,目前仅支持统计一个文件夹,再次添加会覆盖
27 | 2. 过滤功能只对文件夹生效,在弹窗中按enter添加,注意添加后缀名必须带上点
28 | 3. 注释规则文件名不需要带点,规则分为多行注释和单行注释,非必填,一个后缀名文件可以添加多个规则,但不可重复。
29 | 4. 软件默认过滤`node_modules`和`.git`两个文件夹。
30 | 5. 软件默认提供js、ts、go、jsx、tsx、vue、svelte、html、css、java、vue、c和cpp等后缀名文件的注释规则
31 | 6. 读取代码的原理其实是将目标文件的buffer转换成utf-8的string,所以只支持uft-8编码的文件,。大多数code的编码格式是utf-8。
32 |
33 | ### Download
34 | > 见[release](https://github.com/alanchenchen/CodeCounter/releases)
35 |
36 | ### Directory Tree
37 | ``` bash
38 | ├─build 编译平台相关的配置文件、可执行程序
39 | ├─count code counter的主要go module
40 | ├─frontend wails展示的前端静态资源,wails不强关联前端框架和构建工具
41 | │ ├─src
42 | │ └─wailsjs wails在加载静态资源时自动生成的方法bindings,见wails文档
43 | │ ├─index.html
44 | │ ├─package.json
45 | │ └─vite.config.js vite config配置
46 | ├─screenshot
47 | ├─scripts wails的常用命令组合的shell脚本,见wails文档
48 | ├─app.go wails程序的app结构体,主要用于绑定go方法到js运行时,见wails文档
49 | ├─main.go wails程序的入口,初始化,见wails文档
50 | └─wails.json wails cli打包程序需要的配置,见wails文档
51 | ```
52 |
53 | ### Development Setup
54 | #### Required dependencies
55 | - Go 1.17+
56 | - wails v2 beta+
57 | - NPM (Node 15+)
58 | > 详细见[wails文档](https://wails.io/zh-Hans/docs/gettingstarted/installation)
59 |
60 | #### Dev liveload
61 | 项目逻辑分为前端和后端
62 | - 前端可以使用任意框架,兼容性不用过于考虑,因为windows平台使用的webview2(和chromium一致),前端使用go绑定方法也十分简单,都是挂载windows对象
63 | - 后端的go方法可以使用任意go module,当需要绑定给js运行时,只需要在`app.go`里扩展App struct的接收器方法即可
64 | - 如果需要在程序运行中使用前端项目的hot load热更新,必须要先打开一个终端运行`wails dev`,然后另一个终端运行`npm run dev`
65 | - wails读取前端静态资源的策略比较奇怪,所以不建议使用wails的frontend构建
66 |
67 | #### Build
68 | ```bash
69 | # 使用upx压缩打包
70 | $ wails build --upx
71 | ```
72 | - target是mac平台
73 | - 本机必须是mac系统,可以同时编译amd64、arm64架构
74 | - target是windows平台
75 | - 只能编译windows,可以同时编译amd64、arm64架构
76 |
77 | - 所有平台均可使用upx来压缩,压缩比例非常强
78 | - mac平台编译完的是app文件,windows默认编译完的是exe,所有平台均可使用nsis来打包exe
79 | - wails使用的方案是系统自带的webview,目前macos/linux主流版本均内置,windows平台使用的webview2只在部分win10和正式win11内置,所以当你的windwos系统中不存在webview2时,程序启动后会引导你安装,大概118M左右
80 |
--------------------------------------------------------------------------------
/app.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "code-counter/count"
5 | "context"
6 | "os"
7 | "path/filepath"
8 |
9 | "github.com/wailsapp/wails/v2/pkg/runtime"
10 | )
11 |
12 | // App application struct
13 | type App struct {
14 | ctx context.Context
15 | }
16 |
17 | type CustomCommentRules map[string][]count.CommentRule
18 |
19 | // NewApp creates a new App application struct
20 | func NewApp() *App {
21 | return &App{}
22 | }
23 |
24 | // ---- app lifeCycle ----
25 |
26 | // startup is called at application startup
27 | func (a *App) startup(ctx context.Context) {
28 | // Perform your setup here
29 | a.ctx = ctx
30 | }
31 |
32 | // domReady is called after the front-end dom has been loaded
33 | func (a *App) domReady(ctx context.Context) {
34 | // Add your action here
35 | runtime.WindowShow(a.ctx)
36 | }
37 |
38 | // beforeClose is called when the application is about to quit,
39 | // either by clicking the window close button or calling runtime.Quit.
40 | // Returning true will cause the application to continue,
41 | // false will continue shutdown as normal.
42 | func (a *App) beforeClose(ctx context.Context) (prevent bool) {
43 | return false
44 | }
45 |
46 | // shutdown is called at application termination
47 | func (a *App) shutdown(ctx context.Context) {
48 | // Perform your teardown here
49 | }
50 |
51 | // ---- app native go methods bindings to js ----
52 |
53 | // Quit will quit the application
54 | func (a *App) Quit() {
55 | runtime.Quit(a.ctx)
56 | }
57 |
58 | // ReadCodeLinesByDirFiles calculate code counter from dir, return counter data
59 | func (a *App) ReadCodeLinesByDirFiles(dir string, exclude []string, customRules CustomCommentRules) ([]count.FileCodeCounter, error) {
60 | // 合并customRules到count.DefaultRuleConfig,customRules优先级更高
61 | // 必须初始化一个map,而不是直接赋值count.DefaultRuleConfig
62 | // map是指针传递,这样会改变count.DefaultRuleConfig原值
63 | fileRules := make(CustomCommentRules)
64 | for k, v := range count.DefaultRuleConfig {
65 | fileRules[k] = v
66 | }
67 | for k, v := range customRules {
68 | fileRules[k] = v
69 | }
70 | // 合并exclude到count.ExcludePaths
71 | excludeList := append(count.ExcludePaths, exclude...)
72 |
73 | lineCounters, err := count.ReadCodeLinesByDirFiles(dir, excludeList, fileRules)
74 |
75 | res := make([]count.FileCodeCounter, 0)
76 | for countData := range lineCounters {
77 | res = append(res, countData)
78 | }
79 | return res, err
80 | }
81 |
82 | // OpenDialog show a system dialog to choose a file directory
83 | func (a *App) OpenDirectoryDialog(dialogOptions runtime.OpenDialogOptions) (string, error) {
84 | return runtime.OpenDirectoryDialog(a.ctx, dialogOptions)
85 | }
86 |
87 | // SaveFileDialog show a system dialog to choose a saving file path
88 | func (a *App) SaveFileDialog(dialogOptions runtime.SaveDialogOptions) (string, error) {
89 | return runtime.SaveFileDialog(a.ctx, dialogOptions)
90 | }
91 |
92 | // WriteFile write string data to path
93 | func (a *App) WriteFile(path string, data string) error {
94 | // 创建文件
95 | file, err := os.Create(path)
96 | if err != nil {
97 | return err
98 | }
99 | defer file.Close()
100 | // 写入buf到文件
101 | _, writeErr := file.Write([]byte(data))
102 | if writeErr != nil {
103 | return writeErr
104 | }
105 | return nil
106 | }
107 |
108 | // Extname return path ext name
109 | func (a *App) Extname(path string) string {
110 | return filepath.Ext(path)
111 | }
112 |
--------------------------------------------------------------------------------
/build/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/build/.DS_Store
--------------------------------------------------------------------------------
/build/README.md:
--------------------------------------------------------------------------------
1 | # Build Directory
2 |
3 | The build directory is used to house all the build files and assets for your application.
4 |
5 | The structure is:
6 |
7 | * bin - Output directory
8 | * dialog - Icons for dialogs
9 | * tray - Icons for the system tray
10 | * mac - MacOS specific files
11 | * linux - Linux specific files
12 | * windows - Windows specific files
13 |
14 | ## Dialog Icons
15 |
16 | Place any PNG file in this directory to be able to use them in message dialogs.
17 | The files should have names in the following format: `name[-(light|dark)][2x].png`
18 |
19 | Examples:
20 |
21 | * `mypic.png` - Standard definition icon with ID `mypic`
22 | * `mypic-light.png` - Standard definition icon with ID `mypic`, used when system theme is light
23 | * `mypic-dark.png` - Standard definition icon with ID `mypic`, used when system theme is dark
24 | * `mypic2x.png` - High definition icon with ID `mypic`
25 | * `mypic-light2x.png` - High definition icon with ID `mypic`, used when system theme is light
26 | * `mypic-dark2x.png` - High definition icon with ID `mypic`, used when system theme is dark
27 |
28 | ### Order of preference
29 |
30 | Icons are selected with the following order of preference:
31 |
32 | For High Definition displays:
33 | * name-(theme)2x.png
34 | * name2x.png
35 | * name-(theme).png
36 | * name.png
37 |
38 | For Standard Definition displays:
39 | * name-(theme).png
40 | * name.png
41 |
42 | ## Tray
43 |
44 | Place any PNG file in this directory to be able to use them as tray icons.
45 | The name of the filename will be the ID to reference the image.
46 |
47 | Example:
48 |
49 | * `mypic.png` - May be referenced using `runtime.Tray.SetIcon("mypic")`
50 |
51 | ## Mac
52 |
53 | The `darwin` directory holds files specific to Mac builds, such as `Info.plist`.
54 | These may be customised and used as part of the build. To return these files to the default state, simply delete them and
55 | build with the `-package` flag.
56 |
57 | ## Windows
58 |
59 | The `windows` directory contains the manifest and rc files used when building with the `-package` flag.
60 | These may be customised for your application. To return these files to the default state, simply delete them and
61 | build with the `-package` flag.
--------------------------------------------------------------------------------
/build/appicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/build/appicon.png
--------------------------------------------------------------------------------
/build/darwin/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 | CFBundlePackageTypeAPPL
4 | CFBundleName{{.Info.ProductName}}
5 | CFBundleExecutable{{.Name}}
6 | CFBundleIdentifiercom.alanchenchen.{{.Name}}
7 | CFBundleVersion{{.Info.ProductVersion}}
8 | CFBundleGetInfoString{{.Info.Comments}}
9 | CFBundleShortVersionString{{.Info.ProductVersion}}
10 | CFBundleIconFileiconfile
11 | LSMinimumSystemVersion10.13.0
12 | NSHighResolutionCapabletrue
13 | NSHumanReadableCopyright{{.Info.Copyright}}
14 |
--------------------------------------------------------------------------------
/build/windows/code-counter.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | true/pm
12 | permonitorv2,permonitor
13 |
14 |
15 |
--------------------------------------------------------------------------------
/build/windows/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/build/windows/icon.ico
--------------------------------------------------------------------------------
/build/windows/info.json:
--------------------------------------------------------------------------------
1 | {
2 | "fixed": {
3 | "file_version": "{{.Info.ProductVersion}}"
4 | },
5 | "info": {
6 | "0000": {
7 | "ProductVersion": "{{.Info.ProductVersion}}",
8 | "CompanyName": "{{.Info.CompanyName}}",
9 | "FileDescription": "{{.Info.ProductName}}",
10 | "LegalCopyright": "{{.Info.Copyright}}",
11 | "ProductName": "{{.Info.ProductName}}",
12 | "Comments": "{{.Info.Comments}}"
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/build/windows/installer/project.nsi:
--------------------------------------------------------------------------------
1 | Unicode true
2 |
3 | ####
4 | ## Please note: Template replacements don't work in this file. They are provided with default defines like
5 | ## mentioned underneath.
6 | ## If the keyword is not defined, "wails_tools.nsh" will populate them with the values from ProjectInfo.
7 | ## If they are defined here, "wails_tools.nsh" will not touch them. This allows to use this project.nsi manually
8 | ## from outside of Wails for debugging and development of the installer.
9 | ##
10 | ## For development first make a wails nsis build to populate the "wails_tools.nsh":
11 | ## > wails build --target windows/amd64 --nsis
12 | ## Then you can call makensis on this file with specifying the path to your binary:
13 | ## For a AMD64 only installer:
14 | ## > makensis -DARG_WAILS_AMD64_BINARY=../../bin/app.exe
15 | ## For a ARM64 only installer:
16 | ## > makensis -DARG_WAILS_ARM64_BINARY=../../bin/app.exe
17 | ## For a installer with both architectures:
18 | ## > makensis -DARG_WAILS_AMD64_BINARY=../../bin/app-amd64.exe -DARG_WAILS_ARM64_BINARY=../../bin/app-arm64.exe
19 | ####
20 | ## The following information is taken from the ProjectInfo file, but they can be overwritten here.
21 | ####
22 | ## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}"
23 | ## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}"
24 | ## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}"
25 | ## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}"
26 | ## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}"
27 | ###
28 | ## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe"
29 | ## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
30 | ####
31 | ## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html
32 | ####
33 | ## Include the wails tools
34 | ####
35 | !include "wails_tools.nsh"
36 |
37 | # The version information for this two must consist of 4 parts
38 | VIProductVersion "${INFO_PRODUCTVERSION}.0"
39 | VIFileVersion "${INFO_PRODUCTVERSION}.0"
40 |
41 | VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}"
42 | VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer"
43 | VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}"
44 | VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}"
45 | VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}"
46 | VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}"
47 |
48 | !include "MUI.nsh"
49 |
50 | !define MUI_ICON "../icon.ico"
51 | !define MUI_UNICON "../icon.ico"
52 | # !define MUI_WELCOMEFINISHPAGE_BITMAP "resources/leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314
53 | !define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps
54 | !define MUI_ABORTWARNING # This will warn the user if they exit from the installer.
55 |
56 | !insertmacro MUI_PAGE_WELCOME # Welcome to the installer page.
57 | # !insertmacro MUI_PAGE_LICENSE "resources/eula.txt" # Adds a EULA page to the installer
58 | !insertmacro MUI_PAGE_DIRECTORY # In which folder install page.
59 | !insertmacro MUI_PAGE_INSTFILES # Installing page.
60 | !insertmacro MUI_PAGE_FINISH # Finished installation page.
61 |
62 | !insertmacro MUI_UNPAGE_INSTFILES # Uinstalling page
63 |
64 | !insertmacro MUI_LANGUAGE "English" # Set the Language of the installer
65 |
66 | ## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1
67 | #!uninstfinalize 'signtool --file "%1"'
68 | #!finalize 'signtool --file "%1"'
69 |
70 | Name "${INFO_PRODUCTNAME}"
71 | OutFile "../../bin/${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file.
72 | InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder).
73 | ShowInstDetails show # This will always show the installation details.
74 |
75 | Function .onInit
76 | !insertmacro wails.checkArchitecture
77 | FunctionEnd
78 |
79 | Section
80 | !insertmacro wails.webview2runtime
81 |
82 | SetOutPath $INSTDIR
83 |
84 | !insertmacro wails.files
85 |
86 | CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
87 | CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
88 |
89 | !insertmacro wails.writeUninstaller
90 | SectionEnd
91 |
92 | Section "uninstall"
93 | RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath
94 |
95 | RMDir /r $INSTDIR
96 |
97 | Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk"
98 | Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"
99 |
100 | !insertmacro wails.deleteUninstaller
101 | SectionEnd
102 |
--------------------------------------------------------------------------------
/build/windows/installer/wails_tools.nsh:
--------------------------------------------------------------------------------
1 | # DO NOT EDIT - Generated automatically by `wails build`
2 |
3 | !include "x64.nsh"
4 | !include "WinVer.nsh"
5 | !include "FileFunc.nsh"
6 |
7 | !ifndef INFO_PROJECTNAME
8 | !define INFO_PROJECTNAME "{{.Name}}"
9 | !endif
10 | !ifndef INFO_COMPANYNAME
11 | !define INFO_COMPANYNAME "{{.Info.CompanyName}}"
12 | !endif
13 | !ifndef INFO_PRODUCTNAME
14 | !define INFO_PRODUCTNAME "{{.Info.ProductName}}"
15 | !endif
16 | !ifndef INFO_PRODUCTVERSION
17 | !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}"
18 | !endif
19 | !ifndef INFO_COPYRIGHT
20 | !define INFO_COPYRIGHT "{{.Info.Copyright}}"
21 | !endif
22 | !ifndef PRODUCT_EXECUTABLE
23 | !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
24 | !endif
25 | !ifndef UNINST_KEY_NAME
26 | !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
27 | !endif
28 | !define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}"
29 |
30 | !ifndef REQUEST_EXECUTION_LEVEL
31 | !define REQUEST_EXECUTION_LEVEL "admin"
32 | !endif
33 |
34 | RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
35 |
36 | !ifdef ARG_WAILS_AMD64_BINARY
37 | !define SUPPORTS_AMD64
38 | !endif
39 |
40 | !ifdef ARG_WAILS_ARM64_BINARY
41 | !define SUPPORTS_ARM64
42 | !endif
43 |
44 | !ifdef SUPPORTS_AMD64
45 | !ifdef SUPPORTS_ARM64
46 | !define ARCH "amd64_arm64"
47 | !else
48 | !define ARCH "amd64"
49 | !endif
50 | !else
51 | !ifdef SUPPORTS_ARM64
52 | !define ARCH "arm64"
53 | !else
54 | !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY"
55 | !endif
56 | !endif
57 |
58 | !macro wails.checkArchitecture
59 | !ifndef WAILS_WIN10_REQUIRED
60 | !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later."
61 | !endif
62 |
63 | !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED
64 | !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}"
65 | !endif
66 |
67 | ${If} ${AtLeastWin10}
68 | !ifdef SUPPORTS_AMD64
69 | ${if} ${IsNativeAMD64}
70 | Goto ok
71 | ${EndIf}
72 | !endif
73 |
74 | !ifdef SUPPORTS_ARM64
75 | ${if} ${IsNativeARM64}
76 | Goto ok
77 | ${EndIf}
78 | !endif
79 |
80 | IfSilent silentArch notSilentArch
81 | silentArch:
82 | SetErrorLevel 65
83 | Abort
84 | notSilentArch:
85 | MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}"
86 | Quit
87 | ${else}
88 | IfSilent silentWin notSilentWin
89 | silentWin:
90 | SetErrorLevel 64
91 | Abort
92 | notSilentWin:
93 | MessageBox MB_OK "${WAILS_WIN10_REQUIRED}"
94 | Quit
95 | ${EndIf}
96 |
97 | ok:
98 | !macroend
99 |
100 | !macro wails.files
101 | !ifdef SUPPORTS_AMD64
102 | ${if} ${IsNativeAMD64}
103 | File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}"
104 | ${EndIf}
105 | !endif
106 |
107 | !ifdef SUPPORTS_ARM64
108 | ${if} ${IsNativeARM64}
109 | File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}"
110 | ${EndIf}
111 | !endif
112 | !macroend
113 |
114 | !macro wails.writeUninstaller
115 | WriteUninstaller "$INSTDIR\uninstall.exe"
116 |
117 | SetRegView 64
118 | WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
119 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
120 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
121 | WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
122 | WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
123 | WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
124 |
125 | ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
126 | IntFmt $0 "0x%08X" $0
127 | WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
128 | !macroend
129 |
130 | !macro wails.deleteUninstaller
131 | Delete "$INSTDIR\uninstall.exe"
132 |
133 | SetRegView 64
134 | DeleteRegKey HKLM "${UNINST_KEY}"
135 | !macroend
136 |
137 | # Install webview2 by launching the bootstrapper
138 | # See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment
139 | !macro wails.webview2runtime
140 | !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT
141 | !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime"
142 | !endif
143 |
144 | SetRegView 64
145 | # If the admin key exists and is not empty then webview2 is already installed
146 | ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
147 | ${If} $0 != ""
148 | Goto ok
149 | ${EndIf}
150 |
151 | ${If} ${REQUEST_EXECUTION_LEVEL} == "user"
152 | # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed
153 | ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
154 | ${If} $0 != ""
155 | Goto ok
156 | ${EndIf}
157 | ${EndIf}
158 |
159 | SetDetailsPrint both
160 | DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}"
161 | SetDetailsPrint listonly
162 |
163 | InitPluginsDir
164 | CreateDirectory "$pluginsdir\webview2bootstrapper"
165 | SetOutPath "$pluginsdir\webview2bootstrapper"
166 | File "tmp/MicrosoftEdgeWebview2Setup.exe"
167 | ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install'
168 |
169 | SetDetailsPrint both
170 | ok:
171 | !macroend
--------------------------------------------------------------------------------
/build/windows/wails.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | true/pm
12 | permonitorv2,permonitor
13 |
14 |
15 |
--------------------------------------------------------------------------------
/count/countCode.go:
--------------------------------------------------------------------------------
1 | package count
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | type lineCode struct {
8 | LineNO int `json:"lineNO"`
9 | Code string `json:"code,omitempty"`
10 | CommentFlag string `json:"commentFlag,omitempty"`
11 | }
12 |
13 | type LineCounter struct {
14 | TotalLineNum int `json:"totalLineNum"`
15 | BlankLineNum int `json:"blankLineNum"`
16 | CommentLineNum int `json:"commentLineNum"`
17 | TotalLine []lineCode `json:"totalLineCode"`
18 | BlankLine []lineCode `json:"blankLineCode"`
19 | CommentLine []lineCode `json:"commentLineCode"`
20 | }
21 |
22 | // countCodeWithCache 通过读取string buffer,解析代码文件中的注释行、空白行,
23 | // 必须保证s是utf-8编码
24 | func countCodeWithCache(s string, rules []CommentRule) LineCounter {
25 | var totalLine, blankLine, commentLine []lineCode
26 | // 先去除换行符,拿到每行代码的切片
27 | OSFileEOL := "\n"
28 | lineWithoutEOL := strings.Split(s, OSFileEOL)
29 | // 对于同一行代码,不同注释规则是否开启多行注释,需要分开管理
30 | // 为了减少内存占用,只存储len(rules)长度/容量的切片
31 | enableMultipleComment := make([]bool, len(rules))
32 |
33 | for k, v := range lineWithoutEOL {
34 | commentFlag := ""
35 | lineNO := k + 1
36 | // 需要处理代码中的空格前后缀和CRLF模式下的换行符前后缀
37 | code := strings.Trim(v, "\r\t")
38 |
39 | // TODO:
40 | // 如果空白行在多行注释内,会被处理成空白行
41 | if strings.Compare(code, "") == 0 {
42 | blankLine = append(blankLine, lineCode{lineNO, code, commentFlag})
43 | }
44 |
45 | for i, rule := range rules {
46 | // 单行注释
47 | if strings.Compare(rule.row, "") != 0 &&
48 | strings.HasPrefix(code, rule.row) {
49 | commentFlag = rule.row
50 | commentLine = append(commentLine, lineCode{lineNO, code, commentFlag})
51 | }
52 |
53 | // 避免注释规则为空,若为空,则每行代码均被判断成注释
54 | if strings.Compare(rule.block.start, "") == 0 ||
55 | strings.Compare(rule.block.end, "") == 0 {
56 | continue
57 | }
58 |
59 | // 多行注释
60 | if strings.HasPrefix(code, rule.block.start) ||
61 | strings.HasSuffix(code, rule.block.end) ||
62 | enableMultipleComment[i] {
63 | commentFlag = rule.block.start + rule.block.end
64 | commentLine = append(commentLine, lineCode{lineNO, code, commentFlag})
65 | }
66 |
67 | // 多行注释写在多行
68 | if strings.HasPrefix(code, rule.block.start) &&
69 | !strings.HasSuffix(code, rule.block.end) {
70 | // 开启多行注释
71 | enableMultipleComment[i] = true
72 | } else if strings.HasSuffix(code, rule.block.end) {
73 | // 关闭多行注释
74 | enableMultipleComment[i] = false
75 | }
76 | }
77 | totalLine = append(totalLine, lineCode{lineNO, code, commentFlag})
78 | }
79 |
80 | return LineCounter{
81 | len(totalLine),
82 | len(blankLine),
83 | len(commentLine),
84 | totalLine,
85 | blankLine,
86 | commentLine,
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/count/countFile.go:
--------------------------------------------------------------------------------
1 | package count
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 | "sync"
7 | "unicode/utf8"
8 | )
9 |
10 | type FileCodeCounter struct {
11 | FilePath string `json:"filePath"`
12 | FileType string `json:"fileType"`
13 | Data LineCounter `json:"data,omitempty"`
14 | }
15 |
16 | // 读取单个文件,计算代码空白行、注释行
17 | func readCodeLineByFile(path string, commentRule []CommentRule, msgChan chan<- FileCodeCounter, wg *sync.WaitGroup) {
18 | defer wg.Done()
19 | // 解析代码文件中的空白行、注释行
20 | codeCounter := FileCodeCounter{
21 | path,
22 | "",
23 | LineCounter{},
24 | }
25 | file, _ := os.ReadFile(path)
26 | valid := utf8.Valid(file)
27 | if valid {
28 | codeCounter.FileType = "code"
29 | codeCounter.Data = countCodeWithCache(string(file), commentRule)
30 | } else {
31 | codeCounter.FileType = "binary"
32 | }
33 | msgChan <- codeCounter
34 |
35 | // fmt.Printf("file: \u001b[1;36m%v\u001b[0m, BlankLineNum: %v, CommentLineNum: %v, TotalLineNum: %v\n", filepath.Base(path), lineCounter.BlankLineNum, lineCounter.CommentLineNum, lineCounter.TotalLineNum)
36 | // for _, line := range lineCounter.TotalLine {
37 | // fmt.Printf("line: %v, flag: %q, code: %q\n", line.LineNO, line.CommentFlag, line.Code)
38 | // }
39 | }
40 |
41 | // 读取dir下所有文件,计算代码空白行、注释行,返回一个接收channel,可以多次读取,当所有文件都被计算完成后,channel会自动关闭
42 | func ReadCodeLinesByDirFiles(rootDir string, exclude []string, fileRules map[string][]CommentRule) (<-chan FileCodeCounter, error) {
43 | files, err := ReadDirTree(rootDir, exclude)
44 | wg := new(sync.WaitGroup)
45 | msgChan := make(chan FileCodeCounter, len(files))
46 | if err != nil {
47 | return msgChan, err
48 | }
49 |
50 | for _, file := range files {
51 | extname := filepath.Ext(file)
52 | if len(extname) > 1 {
53 | extname = extname[1:]
54 | }
55 | rule := fileRules[extname]
56 |
57 | wg.Add(1)
58 | go readCodeLineByFile(file, rule, msgChan, wg)
59 | }
60 |
61 | // 文件一边count,一边读取chanel
62 | // 完全的channel pipe,channel带缓冲,不会阻塞多个go routine计算
63 | go func() {
64 | wg.Wait()
65 | // 必须关闭,因为range仅当close chan才跳出
66 | close(msgChan)
67 | }()
68 | return msgChan, nil
69 | }
70 |
--------------------------------------------------------------------------------
/count/countFile_test.go:
--------------------------------------------------------------------------------
1 | package count
2 |
3 | import (
4 | "fmt"
5 | "path/filepath"
6 | "testing"
7 | )
8 |
9 | func BenchmarkCountFileByDir(b *testing.B) {
10 | for i := 0; i < b.N; i++ {
11 | // 读取dir下的文件信息
12 | exclude := []string{"go.mod", ".css", ".scss"}
13 | rootDir, _ := filepath.Abs("./")
14 | filesLineCode, err := ReadCodeLinesByDirFiles(rootDir, exclude, make(map[string][]CommentRule)
15 | if err != nil {
16 | fmt.Println(err)
17 | }
18 | for range filesLineCode {
19 | // fmt.Printf("chan len is %v,chan cap is %v, msg comment NO is %v.\n", len(msgChan), cap(msgChan), msg.CommentLineNum)
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/count/defaultConfig.go:
--------------------------------------------------------------------------------
1 | package count
2 |
3 | // 块注释
4 | type blockComment struct {
5 | start string
6 | end string
7 | }
8 |
9 | // 注释规则
10 | type CommentRule struct {
11 | row string
12 | block blockComment
13 | }
14 |
15 | // 新建文件注释规则
16 | func NewCommentRule(row, blockStart, blockEnd string) CommentRule {
17 | return CommentRule{
18 | row: row,
19 | block: blockComment{blockStart, blockEnd},
20 | }
21 | }
22 |
23 | // 默认的文件注释规则map
24 | var DefaultRuleConfig = make(map[string][]CommentRule)
25 |
26 | // 默认过滤的文件(目录)slice
27 | var ExcludePaths = []string{
28 | "node_modules",
29 | ".git",
30 | ".gitignore",
31 | ".npmignore",
32 | }
33 |
34 | // 初始化文件的默认注释规则 DefaultRuleConfig
35 | func init() {
36 | DefaultRuleConfig["js"] = []CommentRule{
37 | {
38 | row: "//", block: blockComment{start: "/*", end: "*/"},
39 | },
40 | }
41 |
42 | DefaultRuleConfig["ts"] = []CommentRule{
43 | {
44 | row: "//", block: blockComment{start: "/*", end: "*/"},
45 | },
46 | }
47 |
48 | DefaultRuleConfig["go"] = []CommentRule{
49 | {
50 | row: "//", block: blockComment{start: "/*", end: "*/"},
51 | },
52 | }
53 |
54 | DefaultRuleConfig["jsx"] = []CommentRule{
55 | {
56 | row: "//", block: blockComment{start: "/*", end: "*/"},
57 | },
58 | }
59 |
60 | DefaultRuleConfig["tsx"] = []CommentRule{
61 | {
62 | row: "//", block: blockComment{start: "/*", end: "*/"},
63 | },
64 | }
65 |
66 | DefaultRuleConfig["vue"] = []CommentRule{
67 | {
68 | row: "//", block: blockComment{start: "/*", end: "*/"},
69 | },
70 | {
71 | block: blockComment{start: ""},
72 | },
73 | }
74 |
75 | DefaultRuleConfig["svelte"] = []CommentRule{
76 | {
77 | row: "//", block: blockComment{start: "/*", end: "*/"},
78 | },
79 | {
80 | block: blockComment{start: ""},
81 | },
82 | }
83 |
84 | DefaultRuleConfig["html"] = []CommentRule{
85 | {
86 | block: blockComment{start: ""},
87 | },
88 | }
89 |
90 | DefaultRuleConfig["css"] = []CommentRule{
91 | {
92 | block: blockComment{start: "/*", end: "*/"},
93 | },
94 | }
95 |
96 | DefaultRuleConfig["java"] = []CommentRule{
97 | {
98 | row: "//", block: blockComment{start: "/*", end: "*/"},
99 | },
100 | }
101 |
102 | DefaultRuleConfig["c"] = []CommentRule{
103 | {
104 | row: "//", block: blockComment{start: "/*", end: "*/"},
105 | },
106 | }
107 |
108 | DefaultRuleConfig["cpp"] = []CommentRule{
109 | {
110 | row: "//", block: blockComment{start: "/*", end: "*/"},
111 | },
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/count/readDir.go:
--------------------------------------------------------------------------------
1 | package count
2 |
3 | import (
4 | "io/fs"
5 | "os"
6 | "path/filepath"
7 | "strings"
8 | )
9 |
10 | // 读取文件目录下的所有文件(夹)路径,并根据exclude过滤
11 | //
12 | // path:完整的os路径,filepath包拼接
13 | //
14 | // exclude:文件(夹)basename、文件后缀名的列表,例 []string{ "count", "count.go", ".go" }
15 | func ReadDirTree(path string, exclude []string) ([]string, error) {
16 | var readDirErr error
17 | filesList := make([]string, 0)
18 | rootFs := os.DirFS(path)
19 |
20 | walkErr := fs.WalkDir(rootFs, ".", func(p string, d fs.DirEntry, err error) error {
21 | if err != nil {
22 | return fs.SkipDir
23 | }
24 |
25 | basename := d.Name()
26 | extname := filepath.Ext(basename)
27 |
28 | hasInclueds := stringSome(exclude, func(v string) bool {
29 | return strings.Compare(v, basename) == 0 || (!d.IsDir() && strings.Compare(v, extname) == 0)
30 | })
31 | // fmt.Printf("basename: %v, extname: %v, hasInclueds: %v\n", basename, extname, hasInclueds)
32 |
33 | // 如果被exclude匹配到文件(夹)名或文件后缀名,则跳过
34 | if hasInclueds {
35 | if d.IsDir() {
36 | return fs.SkipDir
37 | } else {
38 | return nil
39 | }
40 | }
41 |
42 | // 如果匹配到非exclude的文件名,append
43 | if !d.IsDir() {
44 | fullPath := filepath.Join(path, p)
45 | filesList = append(filesList, fullPath)
46 | }
47 |
48 | return nil
49 | })
50 |
51 | if walkErr != nil {
52 | readDirErr = walkErr
53 | }
54 | return filesList, readDirErr
55 | }
56 |
--------------------------------------------------------------------------------
/count/utils.go:
--------------------------------------------------------------------------------
1 | package count
2 |
3 | import (
4 | "strings"
5 | )
6 |
7 | // slice some with,判断s里面是否存在某项,由withFn完全匹配,v支持string类型,是s的子项
8 | func stringSome(s []string, withFn func(v string) bool) bool {
9 | isInclueded := false
10 | for _, val := range s {
11 | isInclueded = withFn(val)
12 | if isInclueded {
13 | break
14 | }
15 | }
16 | return isInclueded
17 | }
18 |
19 | // slice includes with,判断s里面是否存在r,完全匹配,目前支持 string类型
20 | func stringIncludes(s []string, r string) bool {
21 | return stringSome(s, func(v string) bool {
22 | return strings.Compare(v, r) == 0
23 | })
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/frontend/.DS_Store
--------------------------------------------------------------------------------
/frontend/dist/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/frontend/dist/.gitkeep
--------------------------------------------------------------------------------
/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | code-counter
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "code-counter",
3 | "version": "2.0.1",
4 | "author": "alanchenchen",
5 | "private": true,
6 | "scripts": {
7 | "dev": "vite build --watch",
8 | "build": "vite build"
9 | },
10 | "dependencies": {
11 | "iview": "^2.14.0-rc.4",
12 | "vue": "^2.3.3",
13 | "vue-router": "^3.0.1"
14 | },
15 | "devDependencies": {
16 | "vite-plugin-vue2": "^1.9.3",
17 | "sass": "^1.49.9",
18 | "vite": "^2.8.6",
19 | "vite-plugin-html": "^3.2.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/public/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/frontend/public/.gitkeep
--------------------------------------------------------------------------------
/frontend/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/frontend/src/.DS_Store
--------------------------------------------------------------------------------
/frontend/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ title }}
5 |
13 |
14 |
20 |
21 | 缩放切换
22 | 位移切换
23 |
24 |
25 |
33 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
109 |
110 |
115 |
181 |
--------------------------------------------------------------------------------
/frontend/src/assets/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/frontend/src/assets/github.png
--------------------------------------------------------------------------------
/frontend/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/frontend/src/assets/logo.png
--------------------------------------------------------------------------------
/frontend/src/components/CItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ itemData.title }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
21 |
22 |
23 |
24 |
34 |
35 |
--------------------------------------------------------------------------------
/frontend/src/components/CModal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ modal.title }} 配置
6 |
7 |
8 |
9 |
10 |
11 |
12 |
{{ modal.input.label }}
13 |
20 |
21 |
22 | {{ item }}
32 |
33 |
34 |
35 |
36 |
37 |
62 |
63 |
--------------------------------------------------------------------------------
/frontend/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import App from "./App.vue";
3 | import router from "./router";
4 |
5 | Vue.config.productionTip = false;
6 |
7 | import iView from "iview";
8 | import "iview/dist/styles/iview.css";
9 | Vue.use(iView);
10 |
11 | //路由跳转加入loadingbar全局提示
12 | router.beforeEach((to, from, next) => {
13 | iView.LoadingBar.start();
14 | next();
15 | });
16 |
17 | router.afterEach(route => {
18 | iView.LoadingBar.finish();
19 | });
20 |
21 | new Vue({
22 | render: (h) => h(App),
23 | router
24 | }).$mount("#app");
--------------------------------------------------------------------------------
/frontend/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Router from "vue-router";
2 | import Vue from "vue";
3 |
4 | import Home from "@/views/Home.vue";
5 | import AddFile from "@/views/AddFile.vue";
6 | import ShowResult from "@/views/ShowResult.vue";
7 |
8 | Vue.use(Router);
9 |
10 | export default new Router({
11 | // mode: "hash",
12 | routes: [
13 | {
14 | path: "/",
15 | component: Home
16 | },
17 | {
18 | path: "/addFile",
19 | component: AddFile
20 | },
21 | {
22 | path: "/showResult",
23 | component: ShowResult
24 | }
25 | ]
26 | });
--------------------------------------------------------------------------------
/frontend/src/views/AddFile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
44 |
45 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | {{ commentRule.title }} 配置
62 |
63 |
64 |
65 |
66 |
67 |
{{ input.label }}
68 |
74 |
75 |
76 |
77 |
78 |
79 |
281 |
282 |
308 |
--------------------------------------------------------------------------------
/frontend/src/views/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
CodeCounter
5 |
轻量级统计代码的工具
6 |
7 |
8 | 作者:
9 |
10 |
14 |
15 |
16 |
17 |
18 |
19 |
34 |
35 |
74 |
--------------------------------------------------------------------------------
/frontend/src/views/ShowResult.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 | {{ item }}
7 |
8 |
9 |
17 |
18 |
19 |
20 |
95 |
96 |
--------------------------------------------------------------------------------
/frontend/src/wailsjs/go/models.ts:
--------------------------------------------------------------------------------
1 | export namespace count {
2 |
3 | export class lineCode {
4 | lineNO: number;
5 | code?: string;
6 | commentFlag?: string;
7 |
8 | static createFrom(source: any = {}) {
9 | return new lineCode(source);
10 | }
11 |
12 | constructor(source: any = {}) {
13 | if ('string' === typeof source) source = JSON.parse(source);
14 | this.lineNO = source["lineNO"];
15 | this.code = source["code"];
16 | this.commentFlag = source["commentFlag"];
17 | }
18 | }
19 | export class LineCounter {
20 | totalLineNum: number;
21 | blankLineNum: number;
22 | commentLineNum: number;
23 | totalLineCode: lineCode[];
24 | blankLineCode: lineCode[];
25 | commentLineCode: lineCode[];
26 |
27 | static createFrom(source: any = {}) {
28 | return new LineCounter(source);
29 | }
30 |
31 | constructor(source: any = {}) {
32 | if ('string' === typeof source) source = JSON.parse(source);
33 | this.totalLineNum = source["totalLineNum"];
34 | this.blankLineNum = source["blankLineNum"];
35 | this.commentLineNum = source["commentLineNum"];
36 | this.totalLineCode = this.convertValues(source["totalLineCode"], lineCode);
37 | this.blankLineCode = this.convertValues(source["blankLineCode"], lineCode);
38 | this.commentLineCode = this.convertValues(source["commentLineCode"], lineCode);
39 | }
40 |
41 | convertValues(a: any, classs: any, asMap: boolean = false): any {
42 | if (!a) {
43 | return a;
44 | }
45 | if (a.slice) {
46 | return (a as any[]).map(elem => this.convertValues(elem, classs));
47 | } else if ("object" === typeof a) {
48 | if (asMap) {
49 | for (const key of Object.keys(a)) {
50 | a[key] = new classs(a[key]);
51 | }
52 | return a;
53 | }
54 | return new classs(a);
55 | }
56 | return a;
57 | }
58 | }
59 | export class FileCodeCounter {
60 | filePath: string;
61 | fileType: string;
62 | data?: LineCounter;
63 |
64 | static createFrom(source: any = {}) {
65 | return new FileCodeCounter(source);
66 | }
67 |
68 | constructor(source: any = {}) {
69 | if ('string' === typeof source) source = JSON.parse(source);
70 | this.filePath = source["filePath"];
71 | this.fileType = source["fileType"];
72 | this.data = this.convertValues(source["data"], LineCounter);
73 | }
74 |
75 | convertValues(a: any, classs: any, asMap: boolean = false): any {
76 | if (!a) {
77 | return a;
78 | }
79 | if (a.slice) {
80 | return (a as any[]).map(elem => this.convertValues(elem, classs));
81 | } else if ("object" === typeof a) {
82 | if (asMap) {
83 | for (const key of Object.keys(a)) {
84 | a[key] = new classs(a[key]);
85 | }
86 | return a;
87 | }
88 | return new classs(a);
89 | }
90 | return a;
91 | }
92 | }
93 |
94 |
95 | }
96 |
97 |
--------------------------------------------------------------------------------
/frontend/src/wailsjs/runtime/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@wailsapp/runtime",
3 | "version": "2.0.0",
4 | "description": "Wails Javascript runtime library",
5 | "main": "runtime.js",
6 | "types": "runtime.d.ts",
7 | "scripts": {
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/wailsapp/wails.git"
12 | },
13 | "keywords": [
14 | "Wails",
15 | "Javascript",
16 | "Go"
17 | ],
18 | "author": "Lea Anthony ",
19 | "license": "MIT",
20 | "bugs": {
21 | "url": "https://github.com/wailsapp/wails/issues"
22 | },
23 | "homepage": "https://github.com/wailsapp/wails#readme"
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/src/wailsjs/runtime/runtime.d.ts:
--------------------------------------------------------------------------------
1 | /*
2 | _ __ _ __
3 | | | / /___ _(_) /____
4 | | | /| / / __ `/ / / ___/
5 | | |/ |/ / /_/ / / (__ )
6 | |__/|__/\__,_/_/_/____/
7 | The electron alternative for Go
8 | (c) Lea Anthony 2019-present
9 | */
10 |
11 | export interface Position {
12 | x: number;
13 | y: number;
14 | }
15 |
16 | export interface Size {
17 | w: number;
18 | h: number;
19 | }
20 |
21 | export interface Screen {
22 | isCurrent: boolean;
23 | isPrimary: boolean;
24 | width : number
25 | height : number
26 | }
27 |
28 | // Environment information such as platform, buildtype, ...
29 | export interface EnvironmentInfo {
30 | buildType: string;
31 | platform: string;
32 | arch: string;
33 | }
34 |
35 | // [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
36 | // emits the given event. Optional data may be passed with the event.
37 | // This will trigger any event listeners.
38 | export function EventsEmit(eventName: string, ...data: any): void;
39 |
40 | // [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
41 | export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
42 |
43 | // [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
44 | // sets up a listener for the given event name, but will only trigger a given number times.
45 | export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
46 |
47 | // [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
48 | // sets up a listener for the given event name, but will only trigger once.
49 | export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
50 |
51 | // [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
52 | // unregisters the listener for the given event name.
53 | export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
54 |
55 | // [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
56 | // unregisters all listeners.
57 | export function EventsOffAll(): void;
58 |
59 | // [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
60 | // logs the given message as a raw message
61 | export function LogPrint(message: string): void;
62 |
63 | // [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
64 | // logs the given message at the `trace` log level.
65 | export function LogTrace(message: string): void;
66 |
67 | // [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
68 | // logs the given message at the `debug` log level.
69 | export function LogDebug(message: string): void;
70 |
71 | // [LogError](https://wails.io/docs/reference/runtime/log#logerror)
72 | // logs the given message at the `error` log level.
73 | export function LogError(message: string): void;
74 |
75 | // [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
76 | // logs the given message at the `fatal` log level.
77 | // The application will quit after calling this method.
78 | export function LogFatal(message: string): void;
79 |
80 | // [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
81 | // logs the given message at the `info` log level.
82 | export function LogInfo(message: string): void;
83 |
84 | // [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
85 | // logs the given message at the `warning` log level.
86 | export function LogWarning(message: string): void;
87 |
88 | // [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
89 | // Forces a reload by the main application as well as connected browsers.
90 | export function WindowReload(): void;
91 |
92 | // [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
93 | // Reloads the application frontend.
94 | export function WindowReloadApp(): void;
95 |
96 | // [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
97 | // *Windows only*
98 | // Sets window theme to system default (dark/light).
99 | export function WindowSetSystemDefaultTheme(): void;
100 |
101 | // [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
102 | // *Windows only*
103 | // Sets window to light theme.
104 | export function WindowSetLightTheme(): void;
105 |
106 | // [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
107 | // *Windows only*
108 | // Sets window to dark theme.
109 | export function WindowSetDarkTheme(): void;
110 |
111 | // [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
112 | // Centers the window on the monitor the window is currently on.
113 | export function WindowCenter(): void;
114 |
115 | // [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
116 | // Sets the text in the window title bar.
117 | export function WindowSetTitle(title: string): void;
118 |
119 | // [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
120 | // Makes the window full screen.
121 | export function WindowFullscreen(): void;
122 |
123 | // [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
124 | // Restores the previous window dimensions and position prior to full screen.
125 | export function WindowUnfullscreen(): void;
126 |
127 | // [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
128 | // Returns the state of the window, i.e. whether the window is in full screen mode or not.
129 | export function WindowIsFullscreen(): Promise;
130 |
131 | // [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
132 | // Sets the width and height of the window.
133 | export function WindowSetSize(width: number, height: number): Promise;
134 |
135 | // [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
136 | // Gets the width and height of the window.
137 | export function WindowGetSize(): Promise;
138 |
139 | // [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
140 | // Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
141 | // Setting a size of 0,0 will disable this constraint.
142 | export function WindowSetMaxSize(width: number, height: number): void;
143 |
144 | // [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
145 | // Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
146 | // Setting a size of 0,0 will disable this constraint.
147 | export function WindowSetMinSize(width: number, height: number): void;
148 |
149 | // [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
150 | // Sets the window position relative to the monitor the window is currently on.
151 | export function WindowSetPosition(x: number, y: number): void;
152 |
153 | // [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
154 | // Gets the window position relative to the monitor the window is currently on.
155 | export function WindowGetPosition(): Promise;
156 |
157 | // [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
158 | // Hides the window.
159 | export function WindowHide(): void;
160 |
161 | // [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
162 | // Shows the window, if it is currently hidden.
163 | export function WindowShow(): void;
164 |
165 | // [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
166 | // Maximises the window to fill the screen.
167 | export function WindowMaximise(): void;
168 |
169 | // [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
170 | // Toggles between Maximised and UnMaximised.
171 | export function WindowToggleMaximise(): void;
172 |
173 | // [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
174 | // Restores the window to the dimensions and position prior to maximising.
175 | export function WindowUnmaximise(): void;
176 |
177 | // [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
178 | // Returns the state of the window, i.e. whether the window is maximised or not.
179 | export function WindowIsMaximised(): Promise;
180 |
181 | // [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
182 | // Minimises the window.
183 | export function WindowMinimise(): void;
184 |
185 | // [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
186 | // Restores the window to the dimensions and position prior to minimising.
187 | export function WindowUnminimise(): void;
188 |
189 | // [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
190 | // Returns the state of the window, i.e. whether the window is minimised or not.
191 | export function WindowIsMinimised(): Promise;
192 |
193 | // [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
194 | // Returns the state of the window, i.e. whether the window is normal or not.
195 | export function WindowIsNormal(): Promise;
196 |
197 | // [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
198 | // Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
199 | export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
200 |
201 | // [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
202 | // Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
203 | export function ScreenGetAll(): Promise;
204 |
205 | // [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
206 | // Opens the given URL in the system browser.
207 | export function BrowserOpenURL(url: string): void;
208 |
209 | // [Environment](https://wails.io/docs/reference/runtime/intro#environment)
210 | // Returns information about the environment
211 | export function Environment(): Promise;
212 |
213 | // [Quit](https://wails.io/docs/reference/runtime/intro#quit)
214 | // Quits the application.
215 | export function Quit(): void;
216 |
217 | // [Hide](https://wails.io/docs/reference/runtime/intro#hide)
218 | // Hides the application.
219 | export function Hide(): void;
220 |
221 | // [Show](https://wails.io/docs/reference/runtime/intro#show)
222 | // Shows the application.
223 | export function Show(): void;
224 |
--------------------------------------------------------------------------------
/frontend/src/wailsjs/runtime/runtime.js:
--------------------------------------------------------------------------------
1 | /*
2 | _ __ _ __
3 | | | / /___ _(_) /____
4 | | | /| / / __ `/ / / ___/
5 | | |/ |/ / /_/ / / (__ )
6 | |__/|__/\__,_/_/_/____/
7 | The electron alternative for Go
8 | (c) Lea Anthony 2019-present
9 | */
10 |
11 | export function LogPrint(message) {
12 | window.runtime.LogPrint(message);
13 | }
14 |
15 | export function LogTrace(message) {
16 | window.runtime.LogTrace(message);
17 | }
18 |
19 | export function LogDebug(message) {
20 | window.runtime.LogDebug(message);
21 | }
22 |
23 | export function LogInfo(message) {
24 | window.runtime.LogInfo(message);
25 | }
26 |
27 | export function LogWarning(message) {
28 | window.runtime.LogWarning(message);
29 | }
30 |
31 | export function LogError(message) {
32 | window.runtime.LogError(message);
33 | }
34 |
35 | export function LogFatal(message) {
36 | window.runtime.LogFatal(message);
37 | }
38 |
39 | export function EventsOnMultiple(eventName, callback, maxCallbacks) {
40 | window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
41 | }
42 |
43 | export function EventsOn(eventName, callback) {
44 | EventsOnMultiple(eventName, callback, -1);
45 | }
46 |
47 | export function EventsOff(eventName, ...additionalEventNames) {
48 | return window.runtime.EventsOff(eventName, ...additionalEventNames);
49 | }
50 |
51 | export function EventsOnce(eventName, callback) {
52 | EventsOnMultiple(eventName, callback, 1);
53 | }
54 |
55 | export function EventsEmit(eventName) {
56 | let args = [eventName].slice.call(arguments);
57 | return window.runtime.EventsEmit.apply(null, args);
58 | }
59 |
60 | export function WindowReload() {
61 | window.runtime.WindowReload();
62 | }
63 |
64 | export function WindowReloadApp() {
65 | window.runtime.WindowReloadApp();
66 | }
67 |
68 | export function WindowSetSystemDefaultTheme() {
69 | window.runtime.WindowSetSystemDefaultTheme();
70 | }
71 |
72 | export function WindowSetLightTheme() {
73 | window.runtime.WindowSetLightTheme();
74 | }
75 |
76 | export function WindowSetDarkTheme() {
77 | window.runtime.WindowSetDarkTheme();
78 | }
79 |
80 | export function WindowCenter() {
81 | window.runtime.WindowCenter();
82 | }
83 |
84 | export function WindowSetTitle(title) {
85 | window.runtime.WindowSetTitle(title);
86 | }
87 |
88 | export function WindowFullscreen() {
89 | window.runtime.WindowFullscreen();
90 | }
91 |
92 | export function WindowUnfullscreen() {
93 | window.runtime.WindowUnfullscreen();
94 | }
95 |
96 | export function WindowIsFullscreen() {
97 | return window.runtime.WindowIsFullscreen();
98 | }
99 |
100 | export function WindowGetSize() {
101 | return window.runtime.WindowGetSize();
102 | }
103 |
104 | export function WindowSetSize(width, height) {
105 | window.runtime.WindowSetSize(width, height);
106 | }
107 |
108 | export function WindowSetMaxSize(width, height) {
109 | window.runtime.WindowSetMaxSize(width, height);
110 | }
111 |
112 | export function WindowSetMinSize(width, height) {
113 | window.runtime.WindowSetMinSize(width, height);
114 | }
115 |
116 | export function WindowSetPosition(x, y) {
117 | window.runtime.WindowSetPosition(x, y);
118 | }
119 |
120 | export function WindowGetPosition() {
121 | return window.runtime.WindowGetPosition();
122 | }
123 |
124 | export function WindowHide() {
125 | window.runtime.WindowHide();
126 | }
127 |
128 | export function WindowShow() {
129 | window.runtime.WindowShow();
130 | }
131 |
132 | export function WindowMaximise() {
133 | window.runtime.WindowMaximise();
134 | }
135 |
136 | export function WindowToggleMaximise() {
137 | window.runtime.WindowToggleMaximise();
138 | }
139 |
140 | export function WindowUnmaximise() {
141 | window.runtime.WindowUnmaximise();
142 | }
143 |
144 | export function WindowIsMaximised() {
145 | return window.runtime.WindowIsMaximised();
146 | }
147 |
148 | export function WindowMinimise() {
149 | window.runtime.WindowMinimise();
150 | }
151 |
152 | export function WindowUnminimise() {
153 | window.runtime.WindowUnminimise();
154 | }
155 |
156 | export function WindowSetBackgroundColour(R, G, B, A) {
157 | window.runtime.WindowSetBackgroundColour(R, G, B, A);
158 | }
159 |
160 | export function ScreenGetAll() {
161 | return window.runtime.ScreenGetAll();
162 | }
163 |
164 | export function WindowIsMinimised() {
165 | return window.runtime.WindowIsMinimised();
166 | }
167 |
168 | export function WindowIsNormal() {
169 | return window.runtime.WindowIsNormal();
170 | }
171 |
172 | export function BrowserOpenURL(url) {
173 | window.runtime.BrowserOpenURL(url);
174 | }
175 |
176 | export function Environment() {
177 | return window.runtime.Environment();
178 | }
179 |
180 | export function Quit() {
181 | window.runtime.Quit();
182 | }
183 |
184 | export function Hide() {
185 | window.runtime.Hide();
186 | }
187 |
188 | export function Show() {
189 | window.runtime.Show();
190 | }
191 |
--------------------------------------------------------------------------------
/frontend/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vite";
2 | import { createVuePlugin } from "vite-plugin-vue2";
3 | import path from "path";
4 |
5 | // https://vitejs.dev/config/
6 | export default defineConfig({
7 | plugins: [
8 | createVuePlugin(),
9 | ],
10 | resolve: {
11 | alias: {
12 | "@": path.resolve(__dirname, "src"),
13 | },
14 | },
15 | build: {
16 | rollupOptions: {
17 | output: {
18 | entryFileNames: `assets/[name].js`,
19 | chunkFileNames: `assets/[name].js`,
20 | assetFileNames: `assets/[name].[ext]`,
21 | },
22 | },
23 | },
24 | });
25 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module code-counter
2 |
3 | go 1.19
4 |
5 | require github.com/wailsapp/wails/v2 v2.2.0
6 |
7 | require (
8 | github.com/bep/debounce v1.2.1 // indirect
9 | github.com/go-ole/go-ole v1.2.6 // indirect
10 | github.com/google/uuid v1.1.2 // indirect
11 | github.com/imdario/mergo v0.3.12 // indirect
12 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
13 | github.com/labstack/echo/v4 v4.9.0 // indirect
14 | github.com/labstack/gommon v0.3.1 // indirect
15 | github.com/leaanthony/go-ansi-parser v1.0.1 // indirect
16 | github.com/leaanthony/gosod v1.0.3 // indirect
17 | github.com/leaanthony/slicer v1.5.0 // indirect
18 | github.com/mattn/go-colorable v0.1.11 // indirect
19 | github.com/mattn/go-isatty v0.0.14 // indirect
20 | github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 // indirect
21 | github.com/pkg/errors v0.9.1 // indirect
22 | github.com/samber/lo v1.27.1 // indirect
23 | github.com/tkrajina/go-reflector v0.5.5 // indirect
24 | github.com/valyala/bytebufferpool v1.0.0 // indirect
25 | github.com/valyala/fasttemplate v1.2.1 // indirect
26 | github.com/wailsapp/mimetype v1.4.1 // indirect
27 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
28 | golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect
29 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
30 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
31 | golang.org/x/text v0.3.7 // indirect
32 | )
33 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
2 | github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6 | github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
7 | github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
8 | github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
9 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
10 | github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
11 | github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
12 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
13 | github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
14 | github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
15 | github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
16 | github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
17 | github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
18 | github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
19 | github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
20 | github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
21 | github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
22 | github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
23 | github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
24 | github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
25 | github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
26 | github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
27 | github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
28 | github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
29 | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
30 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
31 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
32 | github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2 h1:acNfDZXmm28D2Yg/c3ALnZStzNaZMSagpbr96vY6Zjc=
33 | github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
34 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
35 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
36 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
37 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
38 | github.com/samber/lo v1.27.1 h1:sTXwkRiIFIQG+G0HeAvOEnGjqWeWtI9cg5/n51KrxPg=
39 | github.com/samber/lo v1.27.1/go.mod h1:it33p9UtPMS7z72fP4gw/EIfQB2eI8ke7GR2wc6+Rhg=
40 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
41 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
42 | github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
43 | github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
44 | github.com/tkrajina/go-reflector v0.5.5 h1:gwoQFNye30Kk7NrExj8zm3zFtrGPqOkzFMLuQZg1DtQ=
45 | github.com/tkrajina/go-reflector v0.5.5/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
46 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
47 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
48 | github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
49 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
50 | github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
51 | github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
52 | github.com/wailsapp/wails/v2 v2.2.0 h1:+zRTNjwqyz1kofT0J2R1FpxXB+m3cZJzW3RjxDgxWNw=
53 | github.com/wailsapp/wails/v2 v2.2.0/go.mod h1:zdc9YVrIijjuNNkLOO3UpTU6M12TJe6TlriL+3ttlMM=
54 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
55 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
56 | golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM=
57 | golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
58 | golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
59 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
60 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
61 | golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
62 | golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
63 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
64 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
65 | golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
66 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
67 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
68 | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
69 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
70 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
71 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
72 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
73 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
74 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
75 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
76 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
77 | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
78 | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
79 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
80 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
81 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
82 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "embed"
5 | "log"
6 |
7 | "github.com/wailsapp/wails/v2/pkg/options/assetserver"
8 | "github.com/wailsapp/wails/v2/pkg/options/mac"
9 |
10 | "github.com/wailsapp/wails/v2"
11 | "github.com/wailsapp/wails/v2/pkg/options"
12 | "github.com/wailsapp/wails/v2/pkg/options/windows"
13 | )
14 |
15 | //go:embed frontend/dist
16 | var assets embed.FS
17 |
18 | //go:embed build/appicon.png
19 | var icon []byte
20 |
21 | func main() {
22 | // Create an instance of the app structure
23 | app := NewApp()
24 |
25 | // Create application with options
26 | err := wails.Run(&options.App{
27 | Title: "Code Counter",
28 | Width: 320,
29 | Height: 550,
30 | DisableResize: true,
31 | Fullscreen: false,
32 | Frameless: true,
33 | StartHidden: true,
34 | HideWindowOnClose: false,
35 | BackgroundColour: options.NewRGBA(255, 255, 255, 0), // 先让背景色透明,然后在页面加载后显示窗口
36 | AssetServer: &assetserver.Options{
37 | Assets: assets,
38 | },
39 | OnStartup: app.startup,
40 | OnDomReady: app.domReady,
41 | OnShutdown: app.shutdown,
42 | Bind: []interface{}{
43 | app,
44 | },
45 | // Windows platform specific options
46 | Windows: &windows.Options{
47 | WebviewIsTransparent: false,
48 | WindowIsTranslucent: false,
49 | DisableWindowIcon: false,
50 | },
51 | Mac: &mac.Options{
52 | TitleBar: mac.TitleBarHiddenInset(),
53 | Appearance: mac.NSAppearanceNameDarkAqua,
54 | WebviewIsTransparent: true,
55 | WindowIsTranslucent: true,
56 | About: &mac.AboutInfo{
57 | Title: "Code Counter",
58 | Message: "© Alan Chen 2022 ",
59 | Icon: icon,
60 | },
61 | },
62 | })
63 |
64 | if err != nil {
65 | log.Fatal(err)
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/screenshot/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/screenshot/.DS_Store
--------------------------------------------------------------------------------
/screenshot/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/screenshot/screenshot1.png
--------------------------------------------------------------------------------
/screenshot/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/screenshot/screenshot2.png
--------------------------------------------------------------------------------
/screenshot/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alanchenchen/CodeCounter/56a6e9a4697231e1b4c5aedb17e2507fd74d661e/screenshot/screenshot3.png
--------------------------------------------------------------------------------
/scripts/build-macos-arm.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo -e "Start running the script..."
4 | cd ../
5 |
6 | echo -e "Start building the app for macos platform..."
7 | wails build -clean -platform darwin/arm64
8 |
9 | echo -e "End running the script!"
10 |
--------------------------------------------------------------------------------
/scripts/build-macos-intel.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo -e "Start running the script..."
4 | cd ../
5 |
6 | echo -e "Start building the app for macos platform..."
7 | wails build -clean -platform darwin
8 |
9 | echo -e "End running the script!"
10 |
--------------------------------------------------------------------------------
/scripts/build-macos.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo -e "Start running the script..."
4 | cd ../
5 |
6 | echo -e "Start building the app for macos platform..."
7 | wails build -clean -platform darwin/universal
8 |
9 | echo -e "End running the script!"
10 |
--------------------------------------------------------------------------------
/scripts/build-windows.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo -e "Start running the script..."
4 | cd ../
5 |
6 | echo -e "Start building the app for windows platform..."
7 | wails build -clean -platform windows/amd64
8 |
9 | echo -e "End running the script!"
10 |
--------------------------------------------------------------------------------
/scripts/build.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo -e "Start running the script..."
4 | cd ../
5 |
6 | echo -e "Start building the app..."
7 | wails build -clean
8 |
9 | echo -e "End running the script!"
10 |
--------------------------------------------------------------------------------
/scripts/install-wails-cli.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | echo -e "Start running the script..."
4 | cd ../
5 |
6 | echo -e "Current Go version: \c"
7 | go version
8 |
9 | echo -e "Install the Wails command line tool..."
10 | go install github.com/wailsapp/wails/v2/cmd/wails@latest
11 |
12 | echo -e "Successful installation!"
13 |
14 | echo -e "End running the script!"
15 |
--------------------------------------------------------------------------------
/wails.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Code Counter",
3 | "assetdir": "frontend/dist",
4 | "frontend:build": "npm run build",
5 | "frontend:install": "npm install",
6 | "frontend:dev": "npm run dev",
7 | "frontend:dev:watcher": "",
8 | "wailsjsdir": "frontend/src",
9 | "version": "2",
10 | "Path": "",
11 | "BuildDir": "",
12 | "outputfilename": "Code Counter",
13 | "OutputType": "",
14 | "Platform": "",
15 | "runNonNativeBuildHooks": false,
16 | "postBuildHooks": null,
17 | "Author": {
18 | "name": "alanchenchen",
19 | "email": "739709491@qq.com"
20 | },
21 | "Info": {
22 | "companyName": "Code Counter",
23 | "productName": "Code Counter",
24 | "productVersion": "2.0.1",
25 | "copyright": "Copyright Alan Chen @2022",
26 | "comments": "Built using Wails (https://wails.app)"
27 | },
28 | "debounceMS": 100,
29 | "devserverurl": "http://localhost:34115",
30 | "appargs": "",
31 | "nsisType": ""
32 | }
--------------------------------------------------------------------------------