== # 외부 PlugIn 확장 ==
외부 프로그램을 실행시켜 텍스트를 처리하게 하는 확장 기능. 이 확장 기능은 [[/매크로모듈화]]처럼 사용자가 각각의 PlugIn 파일을 추가, 삭제, 수정하여 쉽게 덮어 쓸 수 있다.
* 필수 요구 사항:
** [[/LaTeX]]에 있는 UnquoteHtmlForPageContent() 함수가 있을 것
* 선택 요구 사항: 딱히 없다.
=== # 사용법 ===
* 사용법: {{{#!플러그인이름 [옵션들] 내용 }}}
**예를 들어 gnuplot 플러그인이라면,
{{{
{{{#!gnuplot [옵션들...] <-- 한 줄에 오직 이 라인만 있을 것. 플러그인이름은 알파벳,숫자,_ 로만 이뤄짐. 옵션은 공백으로 구분
텍스트 <-- 플러그인이 처리할 텍스트
}}} <-- 역시 한 줄에 이 라인만 있을 것
}}}
* 동작
** 위키는 먼저 ./myplugin/ 디렉토리에서 "플러그인이름.pl"파일(여기서는 gnuplot.pl)을 찾는다. 여기는 사용자가 추가, 수정한 플러그인이 들어간다.
** 없으면 ./plugin/ 디렉토리에서 찾는다. 여기는 ext버전에서 제공하는 플러그인이 들어간다.
** gnuplot.pl 이 있으면, 그 파일을 require 로 부르고, plugin_gnuplot(옵션,텍스트)를 호출한다.
** gnuplot.pl 의 기본 뼈대는 아래와 같다.
{{{#!vim perl
sub plugin_gnuplot {
my ($content, @opt) = @_;
# $content 에는 "텍스트"가, @opt 에는 옵션들의 배열이 전달된다.
# 외부 프로그램을 사용해서 html 출력을 만들어 반환한다.
return "html코드";
}
1; # 마지막에 이 줄이 있어야 한다.
}}}
** 위키는 반환된 html을 StoreRaw()를 거쳐 원문에서 치환한다.
* 에러 처리
** 해당되는 플러그인 파일이 없으면 - "No such plugin found"에러를 내고 원래의 텍스트를 출력
** 플러그인 파일을 불러오는 데 실패하면 - "Failed to load plugin""에러를 내고 원래의 텍스트를 출력
** 플러그인이 불렸는데 플러그인 내에서 에러를 처리하는 경우
*** 플러그인이 undef 를 반환하면 - "Error occurred while processing"에러를 내고 원래의 텍스트를 출력
*** 그 외의 값을 반환하면 - 성공한 경우와 마찬가지로 반환된 스트링을 StoreRaw()를 거쳐 출력한다. 즉 제대로 외부 프로그램이 수행되었는지 아닌지를 구분할 수는 없다. 이런 처리는 각각의 플러그인이 알아서 해 줘야 한다.
* 부작용: 모름 -_-;
* 플러그인을 만들 때 주의할 점들
** plugin의 이름과 외부 프로그램의 이름이 같을 필요는 없다. 플러그인 이름은 플러그인 pl 파일을 만드는 사람 맘.
** 외부 프로그램을 호출하므로, 이 외부 프로그램이 쉘 명령을 실행한다던가 기타 위험한 동작을 하지 않는지 꼼꼼히 확인할 것.
*** 사용자가 넣은 "텍스트"부분의 코드 중에 위험한 부분을 제거해야 한다. (예: gnuplot 에서 "!"으로 시작하면 쉘 명령을 실행한다)
** wiki.pl은 오직 텍스트와 옵션 배열을 넘겨주는 것으로 끝이다. 어떤 옵션을 제공할지, 그림을 생성하는 경우 캐쉬를 사용할지 등등은 각각의 플러그인이 알아서 해야 한다.
=== # wiki.pl 수정 ===
{{{#!vim perl
### 패치를 위해 추가된 환경설정 변수
use vars qw(
...
$PluginDir $MyPluginDir # 추가
...
);
###
}}}
{{{#!vim perl
sub CommonMarkup {
my ($text, $useImage, $doLines) = @_;
local $_ = $text;
if ($doLines < 2) { # 2 = do line-oriented only
###############
### added by gypark
### {{{ }}} 처리
s/(^|\n)\{\{\{[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*\n/&StoreRaw("\n") . &StoreCodeRaw($2) . &StoreRaw("\n<\/PRE>") . "\n"/igem;
### 이 줄 추가
s/(^|\n)\{\{\{#!((\w+)( .+)?)[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*\n/$1.&StorePlugin($2,$5)."\n"/igem;
### {{{lang|n|t }}} 처리
s/(^|\n)\{\{\{([a-zA-Z0-9+]+)(\|(n|\d*|n\d+|\d+n))?[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*\n/&StoreRaw("") . &StoreSyntaxHighlight($2, $4, $5) . &StoreRaw("<\/PRE>") . "\n"/igem;
###
###############
}}}
다음 함수 통채로 추가
{{{#!vim perl
### 외부 plugin 지원
sub StorePlugin {
my ($command, $content) = @_;
my $name;
my @opt;
my $plugin_file = "";;
$command = &UnquoteHtmlForPageContent($command);
@opt = split (/\s/, $command);
$name = shift @opt;
my ($PluginDir, $MyPluginDir) = ("./plugin/", "./myplugin/");
if (-f "$MyPluginDir/$name.pl") {
$plugin_file = "$MyPluginDir/$name.pl";
} elsif (-f "$PluginDir/$name.pl") {
$plugin_file = "$PluginDir/$name.pl";
}
if ($plugin_file eq "") { # 플러그인이 없음
return &StoreRaw("\n").
&StoreRaw("\nNo such plugin found: $name\n").
&StoreCodeRaw($content).
&StoreRaw("\n<\/PRE>") . "\n";
}
my $loadplugin = eval "require '$plugin_file'";
if (not $loadplugin) { # 플러그인 로드에 실패
return &StoreRaw("\n").
&StoreRaw("\nFailed to load plugin: $name\n").
&StoreCodeRaw($content).
&StoreRaw("\n<\/PRE>") . "\n";
}
my $func = "plugin_$name";
my $content_unquoted = &UnquoteHtmlForPageContent($content);
my $txt = &{\&$func}($content_unquoted, @opt);
if (not defined $txt) { # 플러그인이 undef 반환
return &StoreRaw("\n").
&StoreRaw("\nError occurred while processing: $name\n").
&StoreCodeRaw($content).
&StoreRaw("\n<\/PRE>") . "\n";
}
return &StoreRaw($txt);
}
}}}
{{{#!vim perl
sub GetPageLinks {
...
$text =~ s/(.|\n)*?\<\/code>/ /ig;
### {{{ }}} 내의 내용은 태그로 간주하지 않음
$text =~ s/(^|\n)(\{\{\{[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1 \n/igm;
$text =~ s/(^|\n)(\{\{\{([a-zA-Z0-9+]+)(\|(n|\d*|n\d+|\d+n))?[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1 \n/igm;
# 아래 줄 추가
$text =~ s/(^|\n)(\{\{\{#!((\w+)( .+)?)[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1 \n/igm;
###
if ($interlink) {
...
}
}}}
관리자가 페이지 내의 링크를 일괄 변경할 때도 plugin 영역의 내용은 변경하지 않게 한다.
{{{#!vim perl
sub SubstituteTextLinks {
...
$text =~ s/(((.|\n)*?)<\/code>)/&StoreRaw($1)/ige;
$text =~ s/(((.|\n)*?)<\/nowiki>)/&StoreRaw($1)/ige;
###############
### added by gypark
### {{{ }}} 내의 내용은 태그로 간주하지 않음
# 이 아래 처음 두 줄은 조금 수정되었고 세번째 줄 추가됨
$text =~ s/(^|\n)(\{\{\{[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1.&StoreRaw($2)."\n"/igem;
$text =~ s/(^|\n)(\{\{\{([a-zA-Z0-9+]+)(\|(n|\d*|n\d+|\d+n))?[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1.&StoreRaw($2)."\n"/igem;
$text =~ s/(^|\n)(\{\{\{#!((\w+)( .+)?)[ \t\r\f]*\n((.|\n)*?)\n\}\}\}[ \t\r\f]*)\n/$1.&StoreRaw($2)."\n"/igem;
###
###############
...
}
}}}
=== # 추가 업데이트 내역 ===
ext1.72a - 플러그인호출시의 에러처리 개선
ext1.73b - 플러그인이 에러가 나서 원래 텍스트를 보여 줄 때 부등호 등이 치환되어 버리는 문제를 수정
ext1.74a - 미리보기에서 플러그인이 동작하지 않는 문제 수정 (저장된 텍스트를 읽을 때는 줄바꿈이 \n이지만 textarea에 있는 텍스트를 미리보기에 넘겨줄 때는 줄바꿈이 \r\n임)
ext1.75 - 굳이 사용자가 바꿀 일이 없다고 판단되어서, 플러그인 파일이 들어가는 디렉토리 설정을 config 파일에서 제거함.
ext1.95a - {{{#!...}}} 안의 내용 중에 위키네임이나 이중대괄호쌍이 있더라도 그것을 링크로 취급하지 않게 함. (즉, 역링크 검색이나 전체 링크 출력시 표시되지 않게 함)
ext1.110 - ext1.95a와 같은 맥락으로, 관리자 기능 중 링크 일괄 변경을 할 때도 플러그인 안의 내용은 건드리지 않게 함
=== # 사용자 의견 ===
다양한 플러그인이 나오기를 기대합니다~ :-)
----
[[위키위키분류]]