IDE 사용 중에는 소스코드의 함수호출 부분에 ctrl+클릭하면,
자동으로 해당 함수가 정의된 파일을 열어 함수정의부분이 시작되는 라인에 커서를 위치시켜주는 기능이 상당히 편함.
이걸 에디트플러스에서 구현해보고 싶었음.
덧붙여서 ctags로는 할 수 없는, factory method 등이 난무하는 거대규모의 복잡다단한 프로젝트용임을 밝힘.
대략적인 시나리오는 아래와 같음.
1. 에디트플러스에서 사용자도구로 등록된 스크립트 실행 (인수: 파일경로, 라인번호, 커서위치)
2. 스크립트에서 토큰을 추출하여 함수정의부분을 찾아 다시 에디트플러스를 실행.
2번과정에서 포인트는 아래와 같음.
* 에디트플러스는 백그라운드로 실행되어야 함. 그렇지 않으면 에디트플러스가 종료될 때까지 스크립트가 대기상태.
* 이미 실행되어 있는 에디트플러스 창에서 실행되어야 함. 이건 -e 옵션으로가능.
* 에디트플러스 실행시 파일경로, 라인번호 지정가능 해야 함. (OK)
에디트플러스 실행파일의 경로는 C:\Program Files (x86)\EditPlus 3\editplus.exe 이고,
php.exe의 경로는 C:\php\bin\php.exe 이고,
스크립트 파일의 경로는 C:\script\jump_to.php 라고 가정함.
에디트플러스 사용자 도구 설정.
1. 도구 > 사용자 도구구성 클릭.
2. 아래와 같은 형태로 사용자 도구 추가
명령: "C:\php\bin\php.exe" "C:\script\jump_to.php"
인수: "$(FilePath)" $(CurLine) $(CurCol)
'안보이게 실행' 에 체크
개인적으로 추가 단축키로 Alt+방향키UP 을 등록해놓고 사용중.
아래는 위에서 jump_to.php 로 가정한 스크립트 소스.
일단 하나의 파일에 함수호출/정의가 전부 있을 경우엔 아무런 수정없이 바로 동작함.
class method나 autoload 등을 프로젝트에 맞게 구성하여 토큰 추출부분과 위치추출 부분을 수정하면 얼마든지 확장하여 사용이 가능함.
// 파일경로
$filePath = $argv[1];
// 라인번호
$lineNo = (int)$argv[2];
// 커서위치
$cursorPos = (int)$argv[3];
if (file_exists($filePath) === false) {
printf("[ERROR] file does not exists\n%s\n", $filePath);
exit;
}
// 라인 추출
$line = getLine($filePath, $lineNo);
if (!$line) exit;
// 커서위치의 키워드 추출
$keyword = getKeyword($line, $cursorPos);
if (!$keyword) exit;
// 함수위치 추출
$funcPos = getFuncPos($filePath, $keyword);
if (!$funcPos) exit;
// 에디트플러스 실행
runEditPlus($funcPos['file'], $funcPos['line']);
// 지정 파일의 지정라인 추출
function getLine($filePath, $lineNo)
{
if (file_exists($filePath) === false) return false;
$fp = fopen($filePath, 'r');
for ($i=1; $i<$lineNo; $i++) {
$line = fgets($fp);
}
$line = rtrim(fgets($fp));
fclose($fp);
return $line;
}
// 지정된 라인의 커서위치의 키워드 추출
// 현재는 함수명 한 단어만 처리하는 형태
function getKeyword($line, $cursorPos)
{
$len = 0;
$tokenArr = token_get_all("<?php\n".$line);
foreach ($tokenArr as $v) {
if ($v[0] === T_OPEN_TAG) continue;
$cntToken = count($v);
if ($cntToken === 1) $len += strlen($v[0]);
else $len += strlen($v[1]);
if ($len >= $cursorPos) {
if ($cntToken === 1) return $v[0];
else return $v[1];
}
}
return false;
}
// 파일경로를 뒤져서 함수정의 위치 추출
// include_path를 미리 지정하면 재귀호출을 이용해 계속 뒤지는 형태
function getFuncPos($filePath, $funcName)
{
if (file_exists($filePath) === false) return false;
$regex = "/function\s+".$funcName."\s*\(/";
$lineNo = 0;
$lineFunc = -1;
$fp = fopen($filePath, 'r');
while (($line = fgets($fp)) !== false) {
++$lineNo;
$line = rtrim($line);
if (!$line) continue;
preg_match($regex, $line, $match);
if (count($match) < 1) continue;
$lineFunc = $lineNo;
break;
}
fclose($fp);
// 못 찾았음. include_path 등 다른 곳을 뒤지자.
if ($lineFunc === -1) {
// 다음 파일 가져오기
$filePath = getNextFile($filePath);
if (!$filePath) return false;
return getFuncPos($filePath, $funcName);
}
// 찾았음.
else {
return array(
'file' => $filePath,
'line' => $lineNo
);
}
}
// include_path의 파일리스트의 다음 파일을 가져오는 pseudo code
// 여길 각 프로젝트에 맞게 잘 구성하면 됨.
function getNextFile($filePath)
{
$includePath = array(
'C:\project\lib\lib.php',
'C:\project\lib\functions.php'
// ... ...
);
if (!in_array($filePath, $includePath)) $k = 0;
else $k = array_search($filePath, $includePath) + 1;
if ($k >= count($includePath)) return false;
return $includePath[$k];
}
// 파일경로와 라인번호를 넘겨 에디트플러스 실행
function runEditPlus($filePath, $lineNo)
{
$editplusPath = 'C:\Program Files (x86)\EditPlus 3\editplus.exe';
$arg = ' & "'.$filePath.' -cursor '.$lineNo.':0 -e"';
// 백그라운드 실행용 vbs
$vbsScript = <<<EOS
Set WshShell = CreateObject("WScript.shell")
WshShell.Run """___CMD___""" ___ARG___, 0, false
Set WshShell = Nothing
EOS;
$vbsScript = str_replace('___CMD___', $editplusPath, $vbsScript);
$vbsScript = str_replace('___ARG___', $arg, $vbsScript);
$vbsFilePath = sys_get_temp_dir().'\\'.uniqid().'.vbs';
file_put_contents($vbsFilePath, $vbsScript);
exec($vbsFilePath);
unlink($vbsFilePath);
}
'PHP' 카테고리의 다른 글
[PHP] 클래스 이름 관련 함수들 (functions about class name) (0) | 2014.12.04 |
---|---|
[PHP] header() 로 redirect 했을 때 HTTP_REFERER가 사라짐. (0) | 2014.10.29 |
[PHP] Windows에서 백그라운드로 커맨드 실행 (PHP exec as background process on Windows) (0) | 2014.10.09 |
[PHP] Windows LoadAverage 알아내기 (0) | 2014.09.05 |
[PHP] CPU 코어수 확인 [Windows/Linux] (NumberOfProcessors) (0) | 2014.09.05 |