// This is a temporary macro. First, check over the // commands to make sure this is what you intended. // Then, to run this macro, switch to the buffer // where you would like to execute it and press C+m C+p. import java.util.regex.*; import java.util.HashSet; import javax.swing.text.html.*; import javax.swing.text.*; static class Tag { int startIndex; //タグの開始位置 int endIndex; //タグの終了位置 boolean blnEmptyTag; boolean blnStartTag; int start_l; //タグ開始ライン int start_s; //タグ開始の開始位置(行の後ろからの位置) int start_e; //タグ開始の終了位置(行の後ろからの位置) int end_l; //タグ終了のライン int end_s; //タグ終了の開始位置(行の後ろからの位置) int end_e; //タグ終了の終了位置(行の後ろからの位置) String tagName; Tag(String src,int startTagIndex) { tagName = null; blnEmptyTag = false; blnStartTag = false; this.startIndex = src.indexOf("<",startTagIndex); if (this.startIndex < 0) { return; } endIndex = src.indexOf(">",this.startIndex + 1); if (endIndex < 0) { return; } setTagInfo(src, this.startIndex, endIndex); } void setTagInfo(String src, int start, int end){ String tagString = src.substring(start, end+1); int length = tagString.length(); int tagNameStart = 1; for (int i = tagNameStart; i < length; i++){ if (tagString.charAt(i) != ' ') { tagNameStart = i; break; } } int tagNameEnd = tagNameStart + 1; for (int i = tagNameEnd; i < length; i++){ if (tagString.charAt(i) == ' ' || i == length-1) { tagNameEnd = i; break; } } tagName = tagString.substring(tagNameStart, tagNameEnd); if (tagName.startsWith("/")){ blnStartTag = false; tagName = tagName.substring(1); } else { blnStartTag = true; } for (int i = length - 2; i >= 0; i--){ if (tagString.charAt(i) != ' '){ if (tagString.charAt(i) == '/') { blnEmptyTag = true; } break; } } } // Tag(int line, int start, int end, String tagName){ // this.tagName = tagName; // setStartInfo(line, start, end); // } boolean isCorrect(){ return tagName != null; } boolean isEmptyTag(){ return blnEmptyTag; } boolean isStartTag(){ return blnStartTag; } void setStartInfo(int line, int start, int end){ this.start_l = line; this.start_s = start; this.start_e = end; } void setEndInfo(int line, int start, int end){ this.end_l = line; this.end_s = start; this.end_e = end; } } // Pattern ptnTagName = Pattern.compile("<(?![\\!\\?\\%])([/]?)([^>/ ]*)(?:.|\n)*?(/)?>"); Vector skipBlocks; Vector error; HashSet noErrorTag; /** Tag クラスのVector を返す */ Vector getTags(int startIndex, int endIndex) { String sourceText = textArea.getText().substring( startIndex, endIndex); Vector vec = new Vector(); Stack tags = new Stack(); // Matcher mtcStartTag = ptnTagName.matcher(sourceText); int line; int endOffset; int startTagIndex = 0; Tag tag, startTag; while (startTagIndex <= endIndex) { tag = new Tag(sourceText, startTagIndex); // startTagIndex = tag.endIndex + 1; startTagIndex = tag.startIndex + 1; if (!tag.isCorrect()){ break; } if (inSkipBlock(tag.startIndex + startIndex)){ continue; } if (tag.isEmptyTag()){ continue; } line = textArea.getLineOfOffset(startIndex + tag.startIndex); // System.out.println("start line " + line); endOffset = textArea.getLineEndOffset(line); tag.setStartInfo(line, endOffset - (tag.startIndex + startIndex), endOffset - (tag.endIndex + startIndex)); // System.out.println(tag.tagName); if (tag.isStartTag()){ // 開始タグ tags.push(tag); } else { // 終了タグ while(!tags.empty()) { startTag = (Tag)(tags.pop()); if (startTag.tagName.equalsIgnoreCase(tag.tagName)) { // System.out.println("end line " + line); startTag.setEndInfo(tag.start_l, tag.start_s, tag.start_e); vec.add(startTag); break; } else { if ( !noErrorTag.contains(startTag.tagName.toLowerCase())) { error.add("looking for start of in " + (tag.start_l + 1) + " line. skip start of <" + startTag.tagName + "> in " + (startTag.start_l + 1) + " line. "); } } } } } tags.clear(); return vec; } void indentTag(int startIndex, int endIndex) { Vector vec = getTags(startIndex, endIndex); int prevStart = -1; int start_l; int end_l; Selection sel; for(int i = 0; i < vec.size(); i++){ Tag tag = (Tag)(vec.get(i)); start = tag.start_l; end = tag.end_l; if (prevStart != start){ if (end - start < 2){ continue; } // sel = new Selection.Range( // buffer.getLineStartOffset(start + 1), // buffer.getLineEndOffset(end - 1) // ); // System.out.println("Start = " + start + " : End = " + end); // textArea.addToSelection(sel); // textArea.shiftIndentRight(); // textArea.selectNone(); shiftRightLines(start, end); prevStart = start; } } vec.clear(); } void shiftRightLines(int start, int end) { int tabSize = buffer.getTabSize(); int indentSize = buffer.getIndentSize(); boolean noTabs = buffer.getBooleanProperty("noTabs"); String spaceChars = StandardUtilities.createWhiteSpace(indentSize ,noTabs ? 0 : tabSize); // int[] lines = new int[end - start - 1]; int cntLine = end - start - 1; for (int i = 0; i < cntLine; i++){ // lines[i] = i + (start + 1); buffer.insert(buffer.getLineStartOffset(i + start + 1), spaceChars); } // System.out.println(noTabs); } /************************************* HTMLのインデントを行わないブロックを検索 **************************************/ boolean inSkipBlock(int offset) { Vector skipBlock; int start, end; int line; Object[] block; Point tagBlock; tagLine = buffer.getLineOfOffset(offset); tagBlock = new Point(tagLine, buffer.getLineEndOffset(tagLine) - offset); for (int i = 0; i < skipBlocks.size(); i++) { skipBlock = (Vector)skipBlocks.get(i); for (int j = 0; j < skipBlock.size(); j++) { block = skipBlock.get(j); // start = buffer.getLineEndOffset(block[0].x) - block[0].y; // end = buffer.getLineEndOffset(block[1].x) - block[1].y; // System.out.println("start " + start); // System.out.println("end " + end); // System.out.println("offset " + offset); // if (offset >= start && offset < end) { // return true; // } // System.out.println("start " + block[0].x + " " + block[0].y); // System.out.println("end " + block[1].x + " " + block[1].y); // System.out.println("offset " + tagBlock.x + " " + tagBlock.y); start = block[0].x - tagBlock.x; if (start == 0){ start = tagBlock.y - block[0].y; } end = block[1].x - tagBlock.x; if (end == 0){ end = tagBlock.y - block[1].y; } if (start <= 0 && end > 0) { // System.out.println("true"); return true; } // System.out.println("false"); if (start > 0) { // System.out.println(j); break; } } } return false; } Vector getSkipBlocks(String text, int startIndex, int endIndex) { Vector skipBlocks = new Vector(); /* JavaScript */ skipBlocks.add( getBlocks(textArea.getText(), startIndex, endIndex, Pattern.compile("