메인 컨텐츠로 가기

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관 보기.

모든 정보가 안전하게 전송되었습니다.

  • 닫기 [x]

Vim 편집기용 사용자 정의 플러그인 개발

Arpan Sen, 선임 소프트웨어 개발자
Arpan은 EDA(Electronic Design Automation) 업계에 몸 담은 소프트웨어 개발자다. 솔라리스, 썬OS, HP-UX, 아이릭스 등과 같은 다양한 유닉스 기종은 물론 리눅스, 마이크로소프트 윈도우까지 다양한 플랫폼을 사용해 왔다. 그의 주된 관심사는 소프트웨어 성능 최적화 기법, 그래프 이론, 병렬 컴퓨팅이다. 기사를 집필하는 이유는 창의적인 욕구를 충족하기 위해서다. Sen은 소프트웨어 시스템 분야에서 대학원 학위를 받았다.
(An IBM developerWorks Contributing Author)

요약:  Perl 및 Python과 같은 Vim의 사용자 정의 스크립팅 언어 및 옵션을 사용하여 시스템 관리 요구에 부응하도록 많이 사용되고 다양한 기능을 갖춘 Vim 편집기를 확장하는 방법을 배워 보십시오.

원문 게재일:  2010 년 11 월 09 일 번역 게재일:   2011 년 2 월 22 일
난이도:  중급 원문:  보기 PDF:  A4 and Letter (103KB | 12 pages)Get Adobe® Reader®
페이지뷰:  3007 회
의견:  


소개

Vim은 최소 규격만 갖춘 인터페이스이지만, 거의 모든 UNIX® 버전에서 가장 많이 사용되는 두 편집기 중 하나이다. 다양한 소프트웨어 개발 및 시스템 관리 요구에 맞춰 Vim을 손쉽게 확장할 수 있다. Vim에는 사용자가 스크립트를 코딩한 다음 Vim으로 스크립트를 로드하는 데 사용할 수 있는 자체적인 스크립트 언어도 있다. 또는 Perl이나 Python과 같은 외부 스크립트 언어를 사용하여 편집기의 기능을 확장할 수도 있다. 이런 스크립트를 모두 합쳐 Vim 플러그인이라고 한다.

사용자 정의 플러그인이 도움이 되는 가장 흔한 상황은 프로그래밍 언어를 강조표시하는 구문이다. Vim을 설치하면 C, C++, Perl 및 Tcl(Vim_Installation_Folder/vim72/syntax를 살펴볼 것)용으로 미리 정의된 다양한 구문 지원이 제공되지만, 때로는 사용자 정의 또는 새 프로그래밍 언어를 위한 추가 지원이 필요하거나 해당 조직의 특정 코딩 표준을 적용할 수 있게 플러그인을 확장할 필요가 있다.

유사하게, 편집기 내부에서 소스를 컴파일하는 기능도 있어 편리하다. Perl 또는 Python 코드용 사용자 정의 플러그인을 만들면 편집기 내에서 소스를 컴파일할 수 있고, 그러면 오류 위에 커서가 놓이므로 개발 시간을 대폭 단축하는 데 도움이 된다.

이 기사에서는 Vim이 사용자 정의 프로그래밍 언어에서 구문을 강조표시하기 위해 제공해야 하는 것을 보여준다. 여기서는 간단한 정규식 사용법에 따라 코딩 규칙을 적용하고 Vim을 이용한 Perl 스크립트 작성으로 이동한다. Vim 내부에서 소스를 컴파일하는 방법을 보여주는 것으로 이 기사를 마무리하겠다.

주: 본 기사에서는 독자들이 Vim, Perl, make 및 정규식에 대한 기본적인 지식이 있는 것으로 가정하고 설명한다. Vim 버전 7.2와 Perl 버전 5.8을 사용하기로 한다.


구문 강조표시

사용자가 직접 작성한 사용자 정의 언어에서 구문을 강조하기 위해 Vim의 내부 스크립팅 엔진을 사용할 것이다. 목록 1에 이 사용자 정의 언어의 몇 가지 키워드가 표시되어 있다.


목록 1. 사용자 정의 프로그래밍 언어의 키워드
	
foreach if then else elsif while repeat until disable 
integer unsigned signed byte 
always initial 

Vim은 syntax keyword <그룹 이름> <키워드 목록> 형식을 이용해 키워드가 되도록 어떤 단어를 연관한다.

여기서 다루는 사용자 정의 언어에 대해, 목록 2의 의사 코드를 사용한다.


목록 2. Vim에서 키워드 정의
	
syntax keyword group1 foreach if then else elsif while 
    repeat until disable integer unsigned signed byte always initial

그 다음, 이 파일을 $HOME에 lang.vim이라는 이름으로 저장한다. 사용자 정의 언어로 작은 코드 스니펫을 편집한다(목록 3 참조).


목록 3. 사용자 정의 프로그래밍 언어로 작성된 코드
	
integer k=0;
repeat (k < 3) begin
    print “hello world” + k + “\n”;
    k = k + 1;
end

Vim 편집기에서 lang.vim을 :source $HOME/lang.vim으로 로드하면 끝이다. 하지만, 좀 기다리면서 문제가 있는지 살펴보고, 아무런 일도 생기지 않는지 확인한다. 구문을 지정했지만, 구문을 어떻게 강조해야 할지에 관한 정보를 입력하지 않았다. 목록 4는 lang.vim 파일의 개선된 버전을 나타낸 것이다.


목록 4. 구문 강조표시를 지원하는 개선된 버전의 lang.vim
	
syntax keyword type1 integer unsigned signed byte
syntax keyword statement1 foreach if then else elsif 
    while repeat until disable always initial
highlight link type1 Type
highlight link statement1 Statement

lang.vim을 다시 로드한다. 그러면 목록 3과 같이 코드에서 구문이 강조표시된다(그림 1 참조). 아래의 그림 1에서는 키워드 integerrepeat가 강조표시되어 있다.


그림 1. 사용자 정의 코드에서 강조표시된 구문
사용자 정의 코드에서 강조표시된 구문

목록 4에서는 정확히 무슨 일을 한 것일까? 다음 두 가지 사항을 이해해야 한다.

  • 사용자는 일반적으로 프로그램에 있는 명령문들(if-then-else, repeat 등)이 데이터 유형(integer, byte 등)과는 다르게 강조표시되어 더 쉽게 읽을 수 있을 것으로 여긴다. 그래서 구문을 적당한 내용을 포함한 여러 그룹으로 분할한다. 예컨대, type1 그룹에는 integer, unsigned, signedbyte 키워드가 들어 있다.
  • Vim에는 특정 색상 구성표와 함께 제공되는 Type, Statement, CommentIdentifier와 같이 미리 정의된 구문 그룹이 있다. highlight 명령은 byte와 같은 키워드에 대해 동일한 색상 구성표가 적용되도록 type1을 Vim의 Type 그룹과 연관한다.

추가 구문 지원

십중팔구의 사용자는 integerINTEGER가 모두 강조표시되도록 언어에서 대/소문자를 구분하지 않기를 바랄 것이다. 또한, // C++ 스타일의 주석에 대한 지원도 추가하고 싶을 것이다. 목록 5는 수정된 lang.vim 파일을 나타낸 것이다.


목록 5. 구문 강조표시를 지원하는 개선된 버전의 lang.vim
	
syntax case ignore
syntax keyword type1 integer unsigned signed byte
syntax keyword statement1 foreach if then else elsif 
    while repeat until disable always initial
syntax match comment1 /\/\/.*/
highlight link type1 Type
highlight link statement1 Statement
highlight link comment1 Comment

syntax case ignore 문이 대/소문자 구분을 하지 않도록 해준다. 키워드를 사용하여 주석을 처리할 수 없으므로, Vim Comment 그룹과 연관할 수 있는 정규식이 필요하다. syntax match <ID> /<패턴>/을 사용하여 정규식을 정의한다. 시작 및 종료 슬래시(/) 사이에서 //로 시작된 것은 무엇이든 그 행의 끝까지 계속되었음을 나타내는 \/\/.* 패턴을 정의했다. 그래서 사용자 정의 언어에서 그림 2에 표시된 코드는 적절히 강조표시된다.


그림 2. 주석 및 대/소문자 구분 무시 기능 지원
주석 및 대/소문자 구분 무시 기능 지원

사용자 정의 코딩 표준 지원

조직별로 특정한 코딩 표준을 처리하기 위해 사용자 정의 플러그인을 손쉽게 확장할 수 있다. 몇 가지 일반적인 지침은 다음과 같다.

  • 코드에는 탭이 없다.
  • 변수 이름은 14자를 초과하면 안 된다.
  • 단일 행의 길이가 80자를 초과하지 않도록 한다.
  • 함수는 100행을 초과할 수 없다.

코드에는 탭이 없음

코드에는 탭이 없다는 가장 간단한 지침부터 시작해보자. 간단히 tab에 대한 ID를 정의한 다음, 그 ID를 Vim의 미리 정의된 Error 태그와 연관한다.

syntax match identifier1 “\t”
highlight link identifier1 Error

그러면 코드에 탭이 있는 경우 어떤 일이 생길까? 그림 3은 탭이 있는 그림 2의 코드를 수정한 코드를 나타낸 것이다.


그림 3. 빨간색으로 탭이 있음을 강조표시한 Vim의 모습
빨간색으로 탭이 있음을 강조표시한 Vim의 모습

그림 3에서는 repeat 바로 뒤의 탭이 빨간색으로 강조표시되어 있는데, 이는 무엇인가 잘못되었음을 사용자에게 분명히 알려주는 역할을 한다.

변수 이름은 14자를 초과하지 말 것

변수 이름의 길이에 대한 지원에는 구문 일치에서 정규식 사용에 대해 더욱 깊은 이해가 요구된다.

syntax match longword1 “\w\{14,}” 
highlight link longword1 Error

여기서, \w는 문자 클래스 [0-9A-Za-z_]를 정의한다. 즉, 모든 숫자, 영문자(대문자 또는 소문자) 또는 밑줄(_)이 허용된다. 다음 시퀀스는 \{14,}인데, 이는 최소 14개의 연속 항목이 일치해야 한다는 뜻이다. 따라서 this_is_a_REAL_long_word1은 ID 길이가 14자를 초과하므로 강조표시되는 반면, this_is_ok_2는 정상적으로 표시된다. 그림 4는 오류가 발생할 때 어떤 모습인지를 나타낸 것이다.


그림 4. 14자를 초과하는 변수 이름이 빨간색으로 표시됨
14자를 초과하는 변수 이름이 빨간색으로 표시됨

그림 4에서는 this_is_a_REAL_long_word1 변수가 (역시 Vim의 기본 색상 프로파일에 따라) 빨간색으로 강조표시되어 사용자에게 무엇인가 잘못되었음을 경고한다.

단일 행의 길이가 80자를 초과하지 않도록 할 것

단일 행의 길이가 80자를 초과하면 너무 길고 복잡하게 느껴져 읽기 어렵다. syntax match를 다시 사용하여 이 정규식에 대한 ID와 Error에 대한 링크를 정의하게 될 것이다. 정규식을 이해하기 어려워서는 안 된다. 캐럿(^)은 한 행의 시작을 표시하고, 달러 기호($)는 한 행의 끝을 표시한다. 그리고 그 사이에 있는 어떤 내용도 80자를 초과하면 오류가 발생한다. 마침표(.)는 행의 끝이 아닌 어떤 문자와 일치함을 표시한다.

syntax match longline1 “^.\{80,}$” 
highlight link longline1 Error

그림 5는 길이가 80자를 초과하여 강조표시된 코드 행을 나타낸 것이다.


그림 5. 행의 길이가 80자를 초과하지 않도록 하기 위한 규칙
행의 길이가 80자를 초과하지 않도록 하기 위한 규칙

그림 5에서는 공식이 워낙 복잡하여 80자를 초과하는 바람에 Vim에서 전체 행이 빨간색으로 강조표시된 것을 알 수 있다. 백스페이스를 입력하여 행 길이가 80자에서 79자로 줄어드는 순간 강조표시는 사라진다.

함수는 100행을 초과하지 말 것

사용자 정의 코딩 규칙 중 마지막 항목은 함수의 길이는 항상 100행 미만으로 유지해야 한다는 것이다. 목록 6은 사용자 정의 프로그래밍 언어에서 정의한 함수를 나타낸 것이다.


목록 6. 사용자 정의 프로그래밍 언어에서 정의한 함수
	
function f (int k, int l) returns float
begin
  f = k * l;
  for (int i=0; i<10; i++)
  begin
      f += sqrt(k) * sqrt(l);
  end
  return f + 2;
endfunction

복잡한 정규식을 고안하거나 Vim에서 미리 정의된 내부 함수를 호출하기보다는 행 수를 검사하기 위해 Perl로 전체 함수를 전달하는 것이 아마 더 쉽고 분명히 더 빠를 것이다. 다음 섹션에서 세부사항을 설명한다.


외부 스크립트 언어를 이용한 Vim 플러그인 작성

Vim은 Perl, Python, Tcl 및 Ruby 스크립트와 연결하기 쉽다. 하지만, 논의의 범위는 Perl로만 한정하기로 한다. Python, Tcl 및 Ruby와의 인터페이스도 사실은 유사하다. 목록 7에서는 어떤 함수의 길이가 100행을 초과하는 경우 오류 메시지를 표시하는 Vim 플러그인을 설명한다.


목록 7. Perl을 사용하여 Vim용 사용자 정의 플러그인 작성
	
perl << EOF
sub checksize 
{
    my $count = 0;
    my $startfunc = 0;
    my $filelen = scalar @_;
    while ($count < $filelen) 
    {
      if ($_[$count] =~ /^function/) 
      {
        $startfunc = $count;
      }
      elsif ($_[$count] =~ /endfunction/)
      {
        if ($count - $startfunc > 100)
	{
	  Vim::Msg($_[$startfunc], "Error");
	}
      }
      ++$count;
    }
}
EOF

function! L1( )
    perl checksize($curbuf->Get(1..$curbuf->Count()))
endfunction 

이 모든 코딩 작업은 앞서 사용한 것과 같은 lang.vim 파일에서 수행한다. 이 플러그인의 뉘앙스는 다음과 같다.

  1. 마커를 사용하여 Vim 스크립트 내부에 Perl 코드를 임베드한다. 이런 마커들은 임의의 이름을 가질 수 있지만 모두 대문자로 된 이름은 안 된다. 목록 7perl << EOF … EOF에서 사용된 마커는 EOF였다. 두 번째 EOF가 행의 첫 번째 열에서 시작하는지 확인한다. 마커를 EOF로 명명할 필요는 없고 어떤 이름으로든 명명할 수 있지만, 첫 번째 열에 대한 규칙은 반드시 지켜야 한다.
  2. 파일의 전체 내용이 Perl 코드로 전달된다. Perl 서브루틴 checksize는 (Perl에서 @_ implicit 배열의 일부로서) 전체 파일을 순회하면서 함수 길이를 계속 검사한다. 이 서브루틴에서는 function이라는 키워드가 나타나면 카운터를 0으로 설정하고, endfunction이라는 키워드가 나타나면 카운터가 100을 초과하는지 검사한다. 함수 길이가 100행을 초과하면 오류 메시지가 표시된다.
  3. Vim 내부에 메시지를 표시해야 하므로, 일반적인 Perl 인쇄 루틴을 사용하여 오류 메시지를 표시할 수 없다. Vim에서는 Perl에 유용한 인터페이스를 제공하는데, 그 세부사항은 참고자료에서 확인할 수 있다. Vim::Msg는 편집기 창 내부의 메시지를 표시한다. 목록 7에서는 잘못된 함수의 첫 번째 행을 표시한다. Vim::Msg에 대한 두 번째 인수는 표시되는 정보의 유형이다. error는 이 정보가 빨간색으로 강조표시됨을 암시한다.
  4. Vim에서 파일 원본을 Perl 코드로 전달하는 함수를 정의한다. $curbuf->Count( )는 현재 버퍼의 행 수를 알려주고, $curbuf->Get(<line1>..<line2>)line1line2에 의해 지정되는 행 사이의 텍스트를 리턴한다. 이 스크립트에서는 현재 버퍼의 첫 행에서 마지막 행으로 내용을 전달한다. 이제 ESC 모드에서 :call L1()을 입력한다. 그러면 바로 잘못된 함수가 나열되는 것을 볼 수 있다.

Vim 내에서 소스 컴파일

Vim에서는 편집기 내부에서 소스를 컴파일할 수 있다. 구문 강조표시 및 사용자 정의 코드 검사와 함께, 이 기능을 통해 Vim을 사용자 정의 통합 개발 환경(IDE)과 가깝게 만들 수 있다. 목록 8에는 몇몇 오류가 있는 C++ 파일이 있다.


목록 8. 정말 난잡한 C++ 코드
	
#include <iostream>
using namespace stdl

class mytags { 
  public:
    int getid(int id=0);
    void setid(int)
  protectd: 
    list<int> tags;
    const list<int>::iterator tag_i;
}

목록 9에는 편집기 내부에서 컴파일하기 위해 Vim에 추가할 수 있는 간결한 다섯 개의 행이 표시되어 있다.


목록 9. F3 키 맵핑으로 편집기 내부의 오류 컴파일 및 표시
	
function! build()
   make 
   cl  “list the errors
endfunction 
map <F3> :call build()<CR>

ESC 모드에서 F3 키를 눌러 소스를 컴파일한다. build() 함수는 Vim 내부에서 make를 호출한 다음, 오류를 표시하는 cl을 호출한다. 첫 번째 오류로 이동하려면 ESC 모드에서 :cfirst를 입력하고, 이후의 모든 오류로 하나씩 이동하려면 :cn을 사용하고, 마지막 오류로 이동하려면 :clast를 입력한다. 기본적으로, Makefile은 소스와 같은 폴더에 있는 것으로 간주된다. 다시 말해, 목록 9에서 build() 함수를 수정하여 Makefile이 있는 폴더로 이동할 수 있기 때문에, 이 중 어떤 것도 필요하지 않다. 또한, 그것만으로도 충분히 쉽게 make로 인수를 전달할 수 있다. 목록 10에서 그 점을 분명히 보여주고 있다.


목록 10. make를 사용하여 소스를 빌드하기 위해 수정한 Vim 스크립트
	
function! build()
   cd /home/arpan/ibm/scripts “go to the folder where Makefile is
   make CC=g++
   cd /home/sources “back to sources
   cl  “list the errors
endfunction 
map <F3> :call build()<CR>

목록 11은 이제 Vim 내부에서 나타나는 오류를 보여준다.


목록 11. Vim 환경 내에서 오류 생성
	
#include <iostream>
using namespace stdl

class mytags { 
  public:
    int getid(int id=0);
    void setid(int)
  protectd: 
    list<int> tags;
    const list<int>::iterator tag_i;
}

t.cpp:4: error: expected namespace-name before "class"
t.cpp:4: error: `<type error>' is not a namespace
t.cpp:4: error: expected `;' before "class"
t.cpp:8: error: expected `;' before "protectd"
t.cpp:10: error: ISO C++ forbids declaration of `list' with no type
t.cpp:10: error: expected `;' before '<' token
t.cpp:6: error: expected unqualified-id at end of input
t.cpp:6: error: expected `,' or `;' at end of input
Press ENTER or type command to continue


구문 파일 설치

$HOME/.vim에서 syntax라는 이름의 폴더를 작성하고 사용자 정의 플러그인을 그 폴더로 복사한다. 예컨대, 사용자 정의 언어가 ml2라는 언어라고 한다면, 이 파일의 이름을 ml2.vim으로 지정한다. 그 다음, $HOME/.vimrc를 편집하고 syntax on 행을 추가한다. 그걸로 끝이다. 이제는 Vim에서 확장자가 ml2인 파일을 열 때마다 해당 구문이 자동으로 강조표시된다. 이 작동에는 명시적인 함수 호출이 포함되지 않으므로, 서브루틴 길이와 같은 빠른 사용자 정의 코드 검사를 위한 키 맵핑을 가지는 것이 좋다.


결론

고공 행진을 하고 있는 통합 IDE가 빠른 개발의 필수 요건은 아니며, Vim은 이런 철학을 충분히 입증하고 있다. Ruby 및 Python과 같은 언어에 대한 인터페이스를 사용하면 Vim으로 웹에 연결하는 것도 가능하다. 본 주제에 관한 추가 자료는 참고자료 섹션을 참조한다.


참고자료

교육

제품 및 기술 얻기

  • Per interface for Vim: Vim용 Perl 인터페이스에 대한 자세한 내용을 확인하고 이 인터페이스를 다운로드할 수 있다.

토론

필자소개

developerWorks Contributing author level

Arpan은 EDA(Electronic Design Automation) 업계에 몸 담은 소프트웨어 개발자다. 솔라리스, 썬OS, HP-UX, 아이릭스 등과 같은 다양한 유닉스 기종은 물론 리눅스, 마이크로소프트 윈도우까지 다양한 플랫폼을 사용해 왔다. 그의 주된 관심사는 소프트웨어 성능 최적화 기법, 그래프 이론, 병렬 컴퓨팅이다. 기사를 집필하는 이유는 창의적인 욕구를 충족하기 위해서다. Sen은 소프트웨어 시스템 분야에서 대학원 학위를 받았다.

잘못된 도움말 신고

부정사용 신고

감사합니다. 이 항목은 운영자가 관심을 표시했습니다.


잘못된 도움말 신고

부정사용 신고

제출실패 신고. 나중에 다시 실행해주세요.


디벨로퍼웍스 로그인


IBM ID가 필요하세요?
IBM ID를 잊으셨습니까?


비밀번호를 잊으셨습니까?
비밀번호 변경

developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


developerWorks에 처음 로그인하면 developerWorks프로파일이 생성됩니다.귀하의 프로파일에서 동의하신 내용이 공개되지만 이 사항은 언제든지 변경 가능합니다. 귀하의 성명(숨김으로 체크되어 있어도 표시됩니다)과 디스플레이 이름은 게시한 컨텐츠나 사이트 엑세스시 표시됩니다.

화면상에 보여지는 닉네임을 정하세요.

처음 developerWorks에 로그인할 때 프로파일이 작성되므로, 이를 위해 디스플레이 이름을 선택해야 합니다. 선택하신 디스플레이 이름은 developerWorks에 게시한 컨텐츠에 표시됩니다.

3글자 이상 31글자 이하의 길이로 사용 가능합니다. dW커뮤니티 내에서는 보안상 이메일주소를 제외한 다른 이름을 지정하셔야 합니다.

3개의 &이나 대쉬를 포함해주시고 31글자내로 제한해주세요.


developerWorks 이용 약관에 동의하시는 경우 제출을 클릭하십시오. 이용 약관.

 


아티클 순위

의견

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=20
Zone=AIX와 UNIX
ArticleID=628262
ArticleTitle=Vim 편집기용 사용자 정의 플러그인 개발
publish-date=11092010
author1-email=arpan@syncad.com
author1-email-cc=

태그

Help
검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오.

태그를 더 많이 보거나 적게 보기 위해 슬라이더 막대를 사용하십시오.

인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다.

내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.

검색 필드를 사용하여 My developerWorks 내에서 해당 태그가 사용된 모든 종류의 컨텐츠를 검색하십시오. 인기 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 최고 인기 태그를 보여줍니다. 내 태그는 특정 컨텐츠 존(예를 들어, 자바, 리눅스, WebSphere)의 귀하의 태그를 보여줍니다.