ICompilationUnitを、変更するコードパターン
Doltengでユーティリティ化している強引なコーディングパターン。
これを見れば、IDocumentとITextFileBufferの関係が見えてくる筈デス。
見えなければ感じて下さい。念を込めて。
ここで、重要なのは、JDTのモデルを触る時には、以下の点について考慮しないといけない事です。
- 現在エディタで開かれているかどうか
- ファイルの実体を変更するかどうか。つまり、エディタ上でCtrl+Zで戻れる様にしたいかどうか。
- IProgressMonitor も忘れずに。要は、進捗報告と、処理のキャンセル可能性を忘れない事。
public class TypeUtil { public static void modifyType(final ICompilationUnit unit, IProgressMonitor monitor, ModifyTypeHandler handler) { IDocument document = null; ITextFileBuffer buffer = null; try { final ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setSource(unit); ASTNode node = parser.createAST(new SubProgressMonitor(monitor, 1)); if (unit.getOwner() != null) { document = new Document(unit.getBuffer().getContents()); } else { buffer = TextFileBufferUtil.acquire(unit); document = buffer.getDocument(); } final ASTRewrite rewrite = ASTRewrite.create(node.getAST()); final ImportsStructure imports = new ImportsStructure(unit); handler.modify(node, rewrite, imports); MultiTextEdit edit = imports.getResultingEdits(document, monitor); edit.addChild(rewrite.rewriteAST(document, unit.getJavaProject() .getOptions(true))); edit.apply(document); if (buffer != null) { buffer.commit(new SubProgressMonitor(monitor, 1), true); } } catch (Exception e) { DoltengCore.log(e); if (buffer != null) { TextFileBufferUtil.release(unit); } } } public interface ModifyTypeHandler { void modify(ASTNode node, ASTRewrite rewrite, ImportsStructure imports); } } public class TextFileBufferUtil { public static ITextFileBuffer acquire(ICompilationUnit cu) { return acquire(cu.getResource()); } public static ITextFileBuffer acquire(IResource resource) { try { if (resource != null && resource.getType() == IResource.FILE) { final IPath path = resource.getFullPath(); FileBuffers.getTextFileBufferManager().connect(path, new NullProgressMonitor()); return FileBuffers.getTextFileBufferManager() .getTextFileBuffer(path); } } catch (CoreException e) { DoltengCore.log(e); } return null; } public static void release(ICompilationUnit cu) { release(cu.getResource()); } public static void release(IResource resource) { try { if (resource != null && resource.getType() == IResource.FILE) { FileBuffers.getTextFileBufferManager().disconnect( resource.getFullPath(), new NullProgressMonitor()); } } catch (CoreException e) { DoltengCore.log(e); } } }
eclipseは、1つの実体であるファイルを、
複数のエディタで開いていたり、
複数のスレッドが同時に変更を行ったりしようとするので、まぁ、何ぞ大変デスナと言う話。
色んな所で開き直って「知らんガナ!」と言ってしまうのも、重要だと思うデス。