|
From: Christopher W. <caw...@us...> - 2006-02-18 16:53:55
|
Update of /cvsroot/rubyeclipse/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28822/src/org/rubypeople/rdt/internal/corext/util Modified Files: CodeFormatterUtil.java Added Files: Strings.java Log Message: overhaul our completion proposal/template code. Now we will apply formatting to templates when inserted! Plus we're closer to the way JDT does things. We still can't use the actual code formatter on the templates (because our old one does a massive replace edit which messes up variables like the cursor placement). The end result is that users should create templates with somewhat proper formatting initially. Index: CodeFormatterUtil.java =================================================================== RCS file: /cvsroot/rubyeclipse/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/corext/util/CodeFormatterUtil.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** CodeFormatterUtil.java 17 Feb 2006 20:23:22 -0000 1.1 --- CodeFormatterUtil.java 18 Feb 2006 16:53:51 -0000 1.2 *************** *** 4,8 **** --- 4,12 ---- import org.eclipse.text.edits.TextEdit; + import org.rubypeople.rdt.core.IRubyProject; + import org.rubypeople.rdt.core.RubyCore; import org.rubypeople.rdt.core.ToolFactory; + import org.rubypeople.rdt.core.formatter.DefaultCodeFormatterConstants; + import org.rubypeople.rdt.internal.corext.Assert; public class CodeFormatterUtil { *************** *** 25,27 **** --- 29,169 ---- indentationLevel, lineSeparator); } + + /** + * Returns the current indent width. + * + * @param project + * the project where the source is used or <code>null</code> if + * the project is unknown and the workspace default should be + * used + * @return the indent width + * @since 0.8.0 + */ + public static int getIndentWidth(IRubyProject project) { + String key; + if (DefaultCodeFormatterConstants.MIXED.equals(getCoreOption(project, + DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) + key = DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE; + else + key = DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE; + + return getCoreOption(project, key, 4); + } + + /** + * Gets the current tab width. + * + * @param project + * The project where the source is used, used for project + * specific options or <code>null</code> if the project is + * unknown and the workspace default should be used + * @return The tab width + */ + public static int getTabWidth(IRubyProject project) { + /* + * If the tab-char is SPACE, FORMATTER_INDENTATION_SIZE is not used by + * the core formatter. We piggy back the visual tab length setting in + * that preference in that case. + */ + String key; + if (RubyCore.SPACE.equals(getCoreOption(project, + DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR))) + key = DefaultCodeFormatterConstants.FORMATTER_INDENTATION_SIZE; + else + key = DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE; + + return getCoreOption(project, key, 4); + } + + /** + * Returns the possibly <code>project</code>-specific core preference + * defined under <code>key</code>. + * + * @param project + * the project to get the preference from, or <code>null</code> + * to get the global preference + * @param key + * the key of the preference + * @return the value of the preference + * @since 0.8.0 + */ + private static String getCoreOption(IRubyProject project, String key) { + if (project == null) return RubyCore.getOption(key); + return project.getOption(key, true); + } + + /** + * Returns the possibly <code>project</code>-specific core preference + * defined under <code>key</code>, or <code>def</code> if the value is + * not a integer. + * + * @param project + * the project to get the preference from, or <code>null</code> + * to get the global preference + * @param key + * the key of the preference + * @param def + * the default value + * @return the value of the preference + * @since 0.8.0 + */ + private static int getCoreOption(IRubyProject project, String key, int def) { + try { + return Integer.parseInt(getCoreOption(project, key)); + } catch (NumberFormatException e) { + return def; + } + } + + /** + * Creates a string that represents the given number of indentation units. + * The returned string can contain tabs and/or spaces depending on the core + * formatter preferences. + * + * @param indentationUnits + * the number of indentation units to generate + * @param project + * the project from which to get the formatter settings, + * <code>null</code> if the workspace default should be used + * @return the indent string + */ + public static String createIndentString(int indentationUnits, IRubyProject project) { + final String tabChar = getCoreOption(project, + DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR); + final int tabs, spaces; + if (RubyCore.SPACE.equals(tabChar)) { + tabs = 0; + spaces = indentationUnits * getIndentWidth(project); + } else if (RubyCore.TAB.equals(tabChar)) { + // indentWidth == tabWidth + tabs = indentationUnits; + spaces = 0; + } else if (DefaultCodeFormatterConstants.MIXED.equals(tabChar)) { + int tabWidth = getTabWidth(project); + int spaceEquivalents = indentationUnits * getIndentWidth(project); + if (tabWidth > 0) { + tabs = spaceEquivalents / tabWidth; + spaces = spaceEquivalents % tabWidth; + } else { + tabs = 0; + spaces = spaceEquivalents; + } + } else { + // new indent type not yet handled + Assert.isTrue(false); + return null; + } + + StringBuffer buffer = new StringBuffer(tabs + spaces); + for (int i = 0; i < tabs; i++) + buffer.append('\t'); + for (int i = 0; i < spaces; i++) + buffer.append(' '); + return buffer.toString(); + } + + public static TextEdit format2(int kind, String string, int indentationLevel, + String lineSeparator, Map options) { + return format2(kind, string, 0, string.length(), indentationLevel, lineSeparator, options); + } } --- NEW FILE: Strings.java --- package org.rubypeople.rdt.internal.corext.util; import org.rubypeople.rdt.core.IRubyProject; public class Strings { /** * Returns the indent of the given string in indentation units. Odd spaces * are not counted. * * @param line * the text line * @param project * the ruby project from which to get the formatter preferences, * or <code>null</code> for global preferences * @since 3.1 */ public static int computeIndentUnits(String line, IRubyProject project) { return computeIndentUnits(line, CodeFormatterUtil.getTabWidth(project), CodeFormatterUtil .getIndentWidth(project)); } /** * Returns the indent of the given string in indentation units. Odd spaces * are not counted. * * @param line * the text line * @param tabWidth * the width of the '\t' character in space equivalents * @param indentWidth * the width of one indentation unit in space equivalents * @since 3.1 */ public static int computeIndentUnits(String line, int tabWidth, int indentWidth) { if (indentWidth == 0) return -1; int visualLength = measureIndentLength(line, tabWidth); return visualLength / indentWidth; } /** * Computes the visual length of the indentation of a * <code>CharSequence</code>, counting a tab character as the size until * the next tab stop and every other whitespace character as one. * * @param line * the string to measure the indent of * @param tabSize * the visual size of a tab in space equivalents * @return the visual length of the indentation of <code>line</code> * @since 3.1 */ public static int measureIndentLength(CharSequence line, int tabSize) { int length = 0; int max = line.length(); for (int i = 0; i < max; i++) { char ch = line.charAt(i); if (ch == '\t') { int reminder = length % tabSize; length += tabSize - reminder; } else if (isIndentChar(ch)) { length++; } else { return length; } } return length; } /** * Indent char is a space char but not a line delimiters. * <code>== Character.isWhitespace(ch) && ch != '\n' && ch != '\r'</code> */ public static boolean isIndentChar(char ch) { return Character.isWhitespace(ch) && !isLineDelimiterChar(ch); } /** * Line delimiter chars are '\n' and '\r'. */ public static boolean isLineDelimiterChar(char ch) { return ch == '\n' || ch == '\r'; } } |