初マクロ

帰省して、やることがないのでマクロを作ってみた。
SVNのCommitマクロを作るつもりだったが、実家からはリポジトリにアクセスできないのでテスト不能
ローカルにリポジトリを作るのも面倒なので休み明けかな。

作ったのはショートカットを開くマクロ。
jFD2はショートカットの作成・削除が簡単で良いのだが、開く時の操作性がDFに比べるといまいちなので、それを改善するのが目標。

機能:ショートカットを開く
(1) 起動した時にショートカットフォルダーにあるショートカットを一覧表示。
(2) その段階でインクリメンタルサーチ(Migemoが使えればMigemo)できる*1
(3) Enterキーで選択したショートカットを開く。
(4) Shift+Enterキーで選択したショートカットを新しいタブで開く。

Swingでちょっとはまった。実家ではネット環境が貧弱なので調べるのも大変。
Groovyではインターフェイスの実装が楽でいいなぁ。KeyAdapterを使わなくてもKeyListenerの実装が簡単にできる。

import com.nullfish.lib.vfs.VFS
import com.nullfish.lib.keymap.KeyStrokeMap
import com.nullfish.app.jfd2.ui.container2.NumberedJFD2
import com.nullfish.app.jfd2.ui.container2.JFD2TitleUpdater
import com.nullfish.app.jfd2.ui.container2.ContainerPosition
import com.nullfish.app.jfd2.util.IncrementalSearcher
import com.nullfish.app.jfd2.util.WildCardUtil
import com.nullfish.app.jfd2.util.MigemoInfo
import org.monazilla.migemo.Migemo
import java.awt.event.KeyListener
import java.awt.event.KeyEvent
import java.awt.event.InputEvent
import java.awt.event.KeyAdapter
import javax.swing.KeyStroke

files=[]
shortcutDir=(String)jfd.getCommonConfigulation().getParam("shortcut_dir", "")
new File(shortcutDir).list().each{
  m=(it=~/(.+)\.jfdlnk$/)
  if(m.size()>0) files<<=m[0][1]
}
if(files.size()<1) return
files=files.sort()
dlg=new groovy.swing.SwingBuilder().dialog(title:"Open shortcut"){
  box(axis:javax.swing.BoxLayout.Y_AXIS){
    scrollPane(){
      ls=list(listData:files,selectionMode:javax.swing.ListSelectionModel.SINGLE_SELECTION,selectedIndex:0)
    }
    panel(){
      label(text:"Search:")
      word=label()
    }
    panel(){
      label(text:"Enter:Open, Shift+Enter:NewTab, ESC:Cancel, Chars:Search")
    }
  }
}

dlg.pack()
dlg.setLocationRelativeTo(null)
dlg.setVisible(true)

ls.addKeyListener([keyPressed:{e->
  setIndex={pos->
    ls.selectedIndex=pos
    ls.ensureIndexIsVisible(pos)
    ls.updateUI()
  }
  searchWord={
    wd=MigemoInfo.usesMigemo()?Migemo.lookup(word.text):"^"+WildCardUtil.wildCard2Regex(word.text).toLowerCase()
    pattern=wd.bitwiseNegate()
    for(i in 0..files.size()-1){
      if(files[i].toLowerCase()=~pattern){
        setIndex(i)
        break
      }
    }
  }

  switch(KeyStrokeMap.getKeyStrokeForEvent(e)){
  case KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0):
  case KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK):
    file=new File(new File(shortcutDir),files[ls.selectedIndex]+".jfdlnk")
    newPath=new String(file.readBytes())
    newFile = VFS.getInstance(jfd).getFile(newPath)
    if(newFile != null){
      if(e.modifiersEx&KeyEvent.SHIFT_DOWN_MASK){
        newJFD = new NumberedJFD2()
        newJFD.init(jfd.jFDOwner.configDirectory)
        jfd.jFDOwner.addComponent(newJFD, ContainerPosition.MAIN_PANEL, new JFD2TitleUpdater(newJFD))
        newJFD.model.setDirectoryAsynchIfNecessary(newFile, newFile.getParent(), newJFD)
      }else{
        jfd.model.setDirectoryAsynchIfNecessary(newFile, newFile.parent, jfd)
      }
    }
  case KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0):
    dlg.dispose()
    break
  case KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0):
  case KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.CTRL_DOWN_MASK):
    switch(word.text.size()){
    case 0:break
    case 1:
      word.text=""
      setIndex(0)
      break
    default:
      word.text=word.text.getAt(0..-2)
      searchWord()
    }
    break
  default:
    c=Character.toUpperCase(e.getKeyChar()).toString()
    if(word.text.size()<30&&IncrementalSearcher.ACCEPTABLE_CHARS.indexOf(c)>=0){
      word.text+=(e.modifiersEx&KeyEvent.SHIFT_DOWN_MASK) ? c:e.getKeyChar().toString()
      searchWord()
    }
  }
}] as KeyListener)

*1:自分の使い方だとMigemoは切った方が良さそう