这个脚本用于将一个脚本中的#include语句包含的脚本添加到这条#include语句的位置。
同时,它有其他功能,如:去除空行、注释(仅单行)、替换内置变量。
因为脚本原理是读取单行并处理,所以只能处理单行注释。
但脚本主要目的就是合并分部分的脚本,方便编译成exe。
当然,写法必须符合正则,比如#nclude的路径必须带引号,即使不使用引号也可以。
另外,另一种解决方法是使用;@Ahk2Exe-AddResource,不过需要手动编写这些引入注释。
; ========
; by wtdkwd 2023/10/21
; ========
; include files see `https://gitee.com/dkwd/ahk.git`
#Requires AutoHotkey v2.0
#SingleInstance Force
#Include 'G:\AHK\gitee_ahk2\common\Extend.ahk'
#Include 'G:\AHK\gitee_ahk2\common\Path.ahk'
require := Map() ; store the require statements
directives := Map()
included := Map()
buildin := Map()
requiresRE := 'i)#requires\s(.*)'
includedRE := 'i)#include\s[`'|"](.*)[`'|"]'
commentRE := '\s*;.*$' ; This RE only handles single-line comments
trailingComment := '^(.*?)\s+;.*?$' ; trailingComment
RemoveComment(&line) { ; Remove the comment
copy := line
if copy ~= commentRE {
copy := ''
} else if RegExMatch(copy, trailingComment, &match) {
copy := match[1]
} else {
copy := copy
}
line := copy
}
ReplaceKeyWord(&input) { ; Remove the buildin keyworlds
copy := input
for k, v in buildin
copy := StrReplace(copy, k, v)
input := copy
}
_Trim(&input) { ; Remove before and after Spaces
copy := input
input := Trim(copy)
}
filters := [_Trim, RemoveComment, ReplaceKeyWord]
_Trim_(singleLine) {
for fn in filters { ; Run filter
fn(&singleLine)
}
return singleLine ? singleLine '`r`n' : ''
}
ConcatPath(curr, _path) {
Path.Normalize(&curr)
Path.Normalize(&_path)
segs := []
curr := StrSplit(curr, Path.Sep)
_path := StrSplit(_path, Path.Sep)
loop _path.Length {
if '..' == _path[A_Index] {
curr.Pop()
} else if '.' != _path[A_Index] && '' != _path[A_Index] {
segs.Push(_path[A_Index])
}
}
return curr.Concat(segs).Join(Path.Sep)
}
Reset() {
global
require.Clear()
directives.Clear()
included.Clear()
}
Resolve(fileFullPath) {
resolved := ''
global currentFile := fileFullPath
currentDir := Path.ParseFilePath(fileFullPath).dir
f := FileOpen(fileFullPath, 'r', 'utf-8')
while !f.AtEOF {
oriLine := f.ReadLine()
if !oriLine ; brank line
continue
line := _Trim_(oriLine)
d.Join line, oriLine
if !line ; brank line
continue
if line ~= '^#' {
if line ~= requiresRE {
RegExMatch(line, requiresRE, &match)
content := match[1]
if require.Has(content)
line := ''
require.set(fileFullPath, content)
} else if line ~= includedRE {
RegExMatch(line, includedRE, &match)
includeFilePath := match[1]
if Path.IsAbsolute(includeFilePath) { ; If it is an absolute path, no processing is needed
resolvedPath := includeFilePath
} else { ; Get the correct absolute path
resolvedPath := ConcatPath(currentDir, includeFilePath)
}
if not included.Has(resolvedPath) {
included.Set(resolvedPath, true)
resolved .= Resolve(resolvedPath) ; Recursive processing
}
line := ''
} else {
directives.Set(fileFullPath, line)
}
}
resolved .= line
}
return resolved
}
#Include 'G:\AHK\gitee_ahk2\common\debug.ahk'
d := Debug('Merge.ahk - A tool for merging partial ahk scripts -- Drag the file you want to merge into the gui', 1600, 800, , , , 'DETAIL', false)
d.Log()
d.OnEvent('DropFiles', OnDropFiles)
OnDropFiles(GuiObj, GuiCtrlObj, FileArray, X, Y) {
d.ClearContent()
Reset()
DroppedFile := FileArray[1]
parsed := Path.ParseFilePath(DroppedFile)
output := parsed.dir Path.Sep parsed.fileName '_Merged.' parsed.ext ; the output path
global currentFile := DroppedFile
global buildin
buildin.Set('A_LineFile', "'" currentFile "'") ; keywords
prefix := A_Space.repeat(14)
d.Join 'filter count: '
d.Join prefix filters.Length
d.Join 'filter funcs: ', 'function name'
for v in filters
d.Join prefix v.Name
d.Join 'buildin info: ', 'The keyword to replace'
for k, v in buildin
d.Join prefix k
d.Divi 'RESOLVE'
result := Resolve(DroppedFile)
d.Divi('RESULT', , true)
subStrings := StrSplit(result, '`r`n')
for v in subStrings
d.Join v, '-'
d.Divi('REQUIRES')
for k, v in require
d.Join v, k
d.Divi('DIRECTIVES')
for k, v in directives
d.Join v, k
d.Divi('INCLUDE')
for k, v in included
d.Join k
d.Log()
f := FileOpen(output, 'w', 'utf-8')
f.Write(result)
f.Close()
MsgBox 'The merged files have been saved to: ' output
}