코딩을 하다보면 기존 프로젝트의 코드를 찾고, 고쳐야 하는 경우도 많이 생긴다. 그래서 IDE들은 다양한 찾기 / 찾아서 바꾸기 기능을 제공한다. IntelliJ 도 댜앙한 찾기 / 바꾸기 기능을 제공하는데, Find Usage
를 제외한 검색 기능은 범위와 수준에 따라 아래와 같이 구분할 수 있다.
- 현재 파일 내부에서 찾기 / 바꾸기
- 전체 파일들에서 찾기 / 바꾸기
- 구조적 찾기 / 바꾸기
- 커스팀 플러그인으로 inspection 을 만들어 찾기
각 기능을 간단히 소개해본다.
현재 파일 내부에서 찾기 / 바꾸기
맥 기준으로 cmd + f / cmd + r 로 현재 선택된 파일 내부에서 문구를 찾고, 바꿀 수 있다. 졍규표현식도 사용할 수 있다. 단순한 기능이라 딱히 더 설명할 내용이 없다.
전체 파일들에서 찾기 / 바꾸기
cmd + shift + f / cmd + shift + r 을 누르면 지정한 scope 내부에서 문구를 찾고, 바꿀 수 있다. 알아두면 좋을 유용한 scope 으로 Files in previous search result
이 있다. 말 그대로 이전 검색 결과 내에서 다시 검색을 하는 기능이다. 예를 들어 Abc 라는 인터페이스의 구현체 중에서 @GET
이 붙어있는 함수와 @POST
가 붙어있는 함수가 모두 포함된 파일 을 찾아야한다면, 간단히 Abc 인터페이스 구현체를 검색하고, 검색 결과를 가진 파일 중에서 @GET
을 검색한 후, 다시 그 결과중에서 @POST
를 검색한 결과 파일들만 뒤져보면 된다.
구조적 찾기 / 바꾸기 (Search Structurally /Replace Structurally)
이 기능은 굉장히 강력한 만큼, 쓰기도 어렵다. IntelliJ 도움말 문서의 항목 을 봐도 하위 항목이 있을 정도로 복잡하다. 맨 땅에서 시작하긴 정말 어려운데, 다행히 기능을 열어보면 여러 템플릿들이 보인다.
템플릿을 선택해서 적절히 modifier 를 조정하면 원하는 검색 결과를 얻을 수 있다. 예를 들어 클래스에 선언된 코틀린 함수 중 이름에 x 가 들어가고, 인자의 갯수가 1개에서 3개 사이이면서 반환 타입은 없는 함수를 찾는다면? 템플릿에서 Kotlin > Class-based > All methods of a class 를 선택한 다음, $ReturnalType$ 은 지우고 $Method$ 엔 Text modifier 를 추가하고, modifier 의 내용엔 정규표현식인 .*x.*
를 넣으면 된다.
이렇게 만든 템플릿은 inspection rule 로 저장할 수도 있다.
modifier 에는 groovy script 도 넣을 수 있다. script가 또 굉장히 강력해서 단순히 대소문자 치환 정도가 아니라 PSI Eleements 를 이용해 이 항목이 변수인지 상수인지 등의 복잡한 판단도 가능하다.
커스팀 플러그인으로 inspection 을 만들어 찾기
구조적 찾기 / 바꾸기에 script modifier 까지 사용하면 다 될 것 같지만 여기에도 한계가 존재한다. 이번에 내가 하고 싶었던 작업은 모든 Koin.get() 함수 호출 중, 타입 인자가 특정 타입이면서 타입 인자가 생략된 경우를 찾고, 생략된 타입 인자를 추가하기 였다. 일단 모든 Koin.get() 를 찾는 건 단순히 find usage 만으로도 가능하다. 그런데 생략된 타입 인자를 찾아서, 채워넣는 부분이 문제였다.
구조적 바꾸기에서 PSI tree 를 이용하면 되지 않을까 싶었는데, 이 경우 타입추론으로 생략된 실제 T 타입을 알아내는 부분에서 막혔다. 실제 타입을 알아내기 위해선 BindingContext
객체가 필요한데, 구조적 검색에선 여기까진 불가능했다. 아니면 단순히 내가 방법을 찾지 못했을 수도 있다. 이렇게 생략된 타입 인자까지 얻어내기 위해선 결국 커스텀 IntelliJ 플러그인을 만들고, 플러그인에서 커스텀 inspection rule 을 만들면 된다.
커스텀 IntelliJ 플러그인을 만드는 것도 성가신 일이긴 한데, 일회성 플러그인이라면 LivePlugin 을 이용하면 간단히 추가할 수 있다. 이 플러그인은 내부에 간단한 플러그인을 만들어넣을 수 있는 플러그인이다. 플러그인 제공 플러그인이라고 해야 하나? 그리고 이 플러그인에 내장된 샘플 중 커스텀 inspection rule 플러그인도 제공하므로 빠르게 시작해 볼 수 있다.
실제 플러그인은 copilot 을 이용해 만들어냈다. 대강 "Koin.get() 함수 중 타입 인자가 생략된 호출을 찾아낸 다음, 생략된 타입 인자를 명시적으로 추가해주는 IntelliJ 플러그인을 작성해줘" 라고 입력하니 잘 만들어줬다. 한번에 실행에 성공하진 못했고, import 문이나 몇 줄 정도는 수정해줬지만 잘 동작했다.
LivePlugin 을 이용해 작성한 plugin 을 실행해서 등록한 후, IntelliJ 의 inspection 기능에서 추가된 inspection rule 을 활성화한 후 code inspection을 실행하니 원하는 검색 결과를 얻을 수 있었다.
구조적 찾기의 한계 - 언제 plugin 이 필요할까
정확하진 않지만, 찾고자 하는 코드의 맥락만으로 판단할 수 있는 검색 조건이라면 구조적 찾기로 가능한 것 같고, 그렇지 않고 타입 추론 등이 필요한 더 복잡한 경우는 커스텀 플러그인까지 만들어야 하는 것 같다.
또 한가지, 커스텀 플러그인의 경우 quick-fix 를 제공할 순 있지만 한번에 찾아서 바꾸는 건 안되는 것 같다. 일일이 inspection 결과에서 눌러서 수정해줘야 한다.
Top comments (0)