首页 > 其他分享 >[AHK2] 将绝对路径导入转化为相对路径导入

[AHK2] 将绝对路径导入转化为相对路径导入

时间:2024-09-12 14:50:04浏览次数:7  
标签:脚本 Log AHK2 ahk 绝对路径 导入 相对路径 Path

问题起源

在使用 AHK 写稍大些的项目时,就会拆分文件,将脚本存放到不同的位置;同时,也会引用别人的工具类等。

这些情况下就会使用#Include导入脚本;可能是绝对路径,也可能是相对路径。

在绝对路径的情况下,想要将项目分享给他人就会带来许多麻烦。因为需要解决绝对路径导入问题

我曾经的做法是写了一个AHK脚本Merge.ahk,将依赖的脚本全部整合到一个脚本中,然后引入即可;但这样做的缺点太明显了,所以没多久就废弃了。

这段时间,我写好了截图工具这个项目将它上传到github上了,就出现了引入脚本的问题;这迫使我写出更好的脚本来处理这种情况。

处理

我的做法是:

  • 将以绝对路径导入的脚本都复制一份,放入到Lib文件夹中;
  • 对于这些脚本,内部使用的#Include脚本同样添加进去。

这样,即解决了路径问题,又保留了可读性,不会对项目造成任何干扰。

运行截图

下面是脚本的运行截图,以脚本本身为例(自己也使用了外部脚本):

其中的包含关系是:

  • IncludeTransfer.ahk 包含 path.ahk 和 extend.ahk
  • path.ahk 包含 extend.ahk
  • extend.ahk 包含 extend/xx.ahk (许多个)

image

将外部脚本映射到lib目录中。
image

形成的目录结构。

image

此时导入路径也修改成正确的路径。

代码

下面的代码可以参考(无法直接运行),也可以访问仓库,我为其独立建立了一个仓库,同时使用此脚本处理了自己,所以可以直接运行。

仓库:https://gitee.com/dkwd/ahk-included-scripts-resolve.git

#Requires AutoHotkey v2.0
; 将以绝对路径导入的文件复制到 ./lib 中
; 对于绝对路径导入的文件,需要将其依赖也导入
#SingleInstance Force

#Include G:\AHK\git-ahk-lib\Path.ahk

libName := '_lib', eof := '`r`n'

g := ResolveGui()
g.Show()

; =============
libPath := '' ; lib 的绝对路径,选择时确定
included := Map() ; 避免重复导入,同时辅助导入文件

statisic := {
  external: 0,
}

filters := [RemoveComment]

includeRE := 'i)^#include\s+([^;\s]+)' ; 匹配导入语句,只支持导入脚本,而其他导入类型**不适用**

; 参数:
; 文件实际路径 | 写入路径 | 父脚本是否为外部脚本
Resolve(_path, _targetPath, _external := false) {
  if !FileExist(_path)
    throw Error('bad filepath: ' _path ' type: ' _external)
  if included.Has(StrLower(_path)) ; 避免重复导入
    return
  included.Set(StrLower(_path), _targetPath)  ; 实际的 : 转换的
  if _external {
    statisic.external++
    g.Log('[E]Mapping: ' _path ' => ' _targetPath)
  } else {
    g.Log('[I]Mapping: ' _path ' => ' _targetPath)
  }

  ; 开始处理
  f := FileOpen(_path, 'r', 'utf-8'), r := ''
  while !f.AtEOF {
    if not l := f.ReadLine() { ; 空行
      r .= eof
      continue
    }

    /* 在此运行过滤器 */
    ; if _external {
    ;   _Trim_(&l)
    ; }

    curDir := Path.Dir(_path)

    if RegExMatch(l, includeRE, &match) {
      ip := Trim(match[1], '[`'|"]') ; 去除可能的引号
      ; 将绝对路径约定为外部脚本;
      ; 如果以绝对路径导入项目中的脚本,将导致该脚本被添加到 lib 目录中(并不会影响运行)
      if Path.IsAbsolute(ip) {

        np := Path.Join(libPath, n := Path.Parse(ip).name) ; 转换为新路径,表示要将内容写到此处
        if _external {
          r .= '#Include ' Path.Relative(Path.Dir(_targetPath), np) eof ; 新的引用路径
        } else {
          r .= '#Include ' Path.Relative(curDir, np) eof
        }

        Resolve(ip, np, true) ; 递归处理
        continue
      } else { ; 相对路径

        np := Path.Join(curDir, ip) ; 计算绝对路径

        ; 如果以 .. 开头,在外部脚本中需要特殊处理;
        ; 而项目脚本不许要,正常处理即可。
        if SubStr(ip, 1, 2) = '..' {

          rp := Path.Join(curDir, ip) ; 计算实际路径

          if _external { ; 如果是外部脚本的相对路径

            if included.Has(_ := StrLower(rp)) { ; 已经包含
              r .= '#Include ' Path.Relative(Path.Dir(_targetPath), _ := included.Get(_)) eof
              Resolve(rp, _, true)
            } else { ; 当作绝对路径处理
              np := Path.Join(libPath, n := Path.Parse(rp).name)
              r .= '#Include ' Path.Relative(Path.Dir(_targetPath), np) eof
              Resolve(rp, np, true)
            }
            continue
          }
        }
        ; ./
        r .= '#Include ' Path.Normalize(ip) eof
        targetDir := Path.Parse(_targetPath).dir
        CreateDirIfNotExist targetDir
        Resolve(np, Path.Join(targetDir, ip), _external)
        continue
      }
    }
    r .= l eof
  }
  f.close()
  f := FileOpen(_targetPath, 'w', 'utf-8') ; 输出
  f.Write(r)
  f.Close()
  return

  _Trim_(_l) {
    for fn in filters
      fn(&_l)
    return _l ? _l '`r`n' : ''
  }
}

CreateDirIfNotExist(dirPath) {
  if !DirExist(dirPath) {
    DirCreate(dirPath)
  }
}

RemoveComment(&line) {
  copy := line
  if copy ~= '^\s*;.*$'
    copy := ''
  else if RegExMatch(copy, '(.*?)\s+;.*?$', &match)
    copy := match[1]
  line := copy
}

class ResolveGui extends Gui {

  f := ''

  __New() {
    super.__New()
    this.SetFont('s14', 'Consolas')
    this.AddText('', 'A simple tool for resolve absolute included ahk scripts.')
    this.AddEdit('ve w1400 h600 ReadOnly')
    this.AddButton('yp section w80', 'Select').OnEvent('click', (*) => this.SelectFile())
    this.AddButton('w80', 'Resolve').OnEvent('Click', (*) => this.Resolve())
    this.OnEvent('DropFiles', (g, ctrl, files, *) => Resolve(files[1], libPath))
  }

  SelectFile(*) {
    f := FileSelect(3, , 'Select a script file', 'Ahk root file(*.ahk)')
    if f {
      if this.f
        this.Log('Entry file has been changed: ' f)
      else
        this.Log('Entry file has been selected: ' f)
      this.Log('Make sure to BACKUP your files before resolving.')
      this.f := f
    }
  }

  Resolve() {
    if !this.f {
      this.Log('Select a file first.')
      return
    }
    global libPath := Path.Join(Path.Dir(this.f), libName)
    CreateDirIfNotExist libPath
    this.Log('==========START==========')
    this.Log('Resolving file: ' this.f)
    Resolve(this.f, this.f)
    this.Log('===========END===========')
    this.Log('========STATISTIC========')
    this.Log('External scripts: ' statisic.external)
    this.Log('Internal scripts: ' included.Count - statisic.external)
    this.Log('===========END===========')
    this.f := ''
  }

  Log(t) => this['e'].Value .= '>> ' t '`n'
}

标签:脚本,Log,AHK2,ahk,绝对路径,导入,相对路径,Path
From: https://www.cnblogs.com/refiz/p/18410157

相关文章