aboutsummaryrefslogtreecommitdiff
path: root/libs/android-syntax-highlight/src
diff options
context:
space:
mode:
authorJorge Ruesga <jorge@ruesga.com>2013-03-25 04:56:38 +0100
committerJorge Ruesga <jorge@ruesga.com>2013-03-27 00:16:04 +0100
commit8573124b80d19a9562a6e623022171b41dc4d183 (patch)
tree40aa0eca71ca3bd4e09abee5efa046f31cc2f308 /libs/android-syntax-highlight/src
parentd063637d6110ab2a762268d7ef20afeaa6f482af (diff)
CMFM: Editor initial highlight support + props syntax processor + others features
- This change enables support of syntax highlight in editor. Adds also the next syntax processors: * PropertiesSyntaxHighlightProcessor - Option for toggle "no suggestion" in editor - CleanUp Patchset 2: Theme color scheme support Patchset 3: Hexdump binary editor preference No suggestions editor preference Syntax Highlight color scheme Add android-syntax-highlight (CMFM) and color-picker-view libraries ColorPickerDialog and ColorPickerPreference Separate preference to its own file Extract themes strings from dark_theme.xml to strings.xml Rebased Change-Id: I9df65e6193d46ebafadee5d545dcde1fc5ce20e9 Signed-off-by: Jorge Ruesga <jorge@ruesga.com>
Diffstat (limited to 'libs/android-syntax-highlight/src')
-rw-r--r--libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/HighlightColors.java121
-rw-r--r--libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/ISyntaxHighlightResourcesResolver.java55
-rw-r--r--libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/RegExpUtil.java71
-rw-r--r--libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/SyntaxHighlightFactory.java96
-rw-r--r--libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/SyntaxHighlightProcessor.java112
-rw-r--r--libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/scanners/NewLineScanner.java76
-rw-r--r--libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/scanners/Scanner.java42
-rw-r--r--libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/spi/PropertiesSyntaxHighlightProcessor.java281
8 files changed, 854 insertions, 0 deletions
diff --git a/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/HighlightColors.java b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/HighlightColors.java
new file mode 100644
index 0000000..5e31dab
--- /dev/null
+++ b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/HighlightColors.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.filemanager.ash;
+
+import android.graphics.Color;
+
+/**
+ * An enumeration of all the color resources available for syntax highlight processors.
+ */
+public enum HighlightColors {
+
+ /**
+ * Text color
+ */
+ TEXT(
+ "ash_text", //$NON-NLS-1$
+ "ash_text_color", //$NON-NLS-1$
+ Color.argb(153, 0, 0, 0)),
+ /**
+ * Assignment text color
+ */
+ ASSIGNMENT(
+ "ash_assignment", //$NON-NLS-1$
+ "ash_assignment_color", //$NON-NLS-1$
+ Color.argb(153, 0, 0, 0)),
+ /**
+ * Single line comment color
+ */
+ SINGLE_LINE_COMMENT(
+ "ash_singleline_comment", //$NON-NLS-1$
+ "ash_singleline_comment_color", //$NON-NLS-1$
+ Color.argb(255, 63, 127, 95)),
+ /**
+ * Multiline line comment color
+ */
+ MULTILINE_LINE_COMMENT(
+ "ash_multiline_comment", //$NON-NLS-1$
+ "ash_multiline_comment_color", //$NON-NLS-1$
+ Color.argb(255, 127, 159, 191)),
+ /**
+ * Keyword color
+ */
+ KEYWORD(
+ "ash_keyword", //$NON-NLS-1$
+ "ash_keyword_color", //$NON-NLS-1$
+ Color.argb(255, 127, 0, 85)),
+ /**
+ * Quoted string color
+ */
+ QUOTED_STRING(
+ "ash_quoted_string", //$NON-NLS-1$
+ "ash_quoted_string_color", //$NON-NLS-1$
+ Color.argb(255, 42, 0, 255)),
+ /**
+ * Variable color
+ */
+ VARIABLE(
+ "ash_variable", //$NON-NLS-1$
+ "ash_variable_color", //$NON-NLS-1$
+ Color.argb(153, 0, 0, 192));
+
+
+ private final String mId;
+ private final String mResId;
+ private final int mDefault;
+
+ /**
+ * Constructor of <code>HighlightColors</code>
+ *
+ * @param id The id of the object
+ * @param resid The resource id
+ * @param def The default value
+ */
+ HighlightColors(String id, String resid, int def) {
+ this.mId = id;
+ this.mResId = resid;
+ this.mDefault = def;
+ }
+
+ /**
+ * Returns the identifier
+ *
+ * @return String The identifier
+ */
+ public String getId() {
+ return this.mId;
+ }
+
+ /**
+ * Returns the resource identifier
+ *
+ * @return String The resource identifier
+ */
+ public String getResId() {
+ return this.mResId;
+ }
+
+ /**
+ * Returns the default value
+ *
+ * @return String The default value
+ */
+ public int getDefault() {
+ return this.mDefault;
+ }
+
+}
diff --git a/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/ISyntaxHighlightResourcesResolver.java b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/ISyntaxHighlightResourcesResolver.java
new file mode 100644
index 0000000..11170e7
--- /dev/null
+++ b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/ISyntaxHighlightResourcesResolver.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.filemanager.ash;
+
+/**
+ * An interface that should be implemented by the library caller, to
+ * resolve resources needed by the syntax processors.
+ *
+ * @see HighlightColors
+ */
+public interface ISyntaxHighlightResourcesResolver {
+
+ /**
+ * Method that returns a string
+ *
+ * @param id The color unique id
+ * @param resid The resource identifier
+ * @return CharSequence The string
+ */
+ CharSequence getString(String id, String resid);
+
+ /**
+ * Method that returns an integer
+ *
+ * @param id The color unique id
+ * @param resid The resource identifier
+ * @param def The default value
+ * @return int The integer value
+ */
+ int getInteger(String id, String resid, int def);
+
+ /**
+ * Method that returns a color
+ *
+ * @param id The color unique id
+ * @param resid The resource identifier
+ * @param def The default value
+ * @return int The color
+ */
+ int getColor(String id, String resid, int def);
+}
diff --git a/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/RegExpUtil.java b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/RegExpUtil.java
new file mode 100644
index 0000000..283eba9
--- /dev/null
+++ b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/RegExpUtil.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.filemanager.ash;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+/**
+ * A helper class for deal with patters
+ */
+public final class RegExpUtil {
+
+ /**
+ * A constant that is returned when the no expression matches.
+ */
+ public static final int NO_MATCH = -1;
+
+ /**
+ * New line pattern
+ */
+ public static final Pattern NEWLINE_PATTERN = Pattern.compile("(\r\n|\n|\r)"); //$NON-NLS-1$
+
+ /**
+ * Method that returns the last match position of a regexp,
+ *
+ * @param pattern The patter
+ * @param input The input
+ * @param withPattern Whether the return position should contains the pattern or not.
+ * @return int The matched position or -1
+ */
+ public static int getLastMatch(Pattern pattern, CharSequence input, boolean withPattern) {
+ Matcher m = pattern.matcher(input);
+ int p = NO_MATCH;
+ while (m.find()) {
+ p = withPattern ? m.start() : m.end();
+ }
+ return p;
+ }
+
+ /**
+ * Method that returns the next match position of a regexp,
+ *
+ * @param pattern The patter
+ * @param input The input
+ * @param withPattern Whether the return position should contains the pattern or not.
+ * @return int The matched position or -1
+ */
+ public static int getNextMatch(Pattern pattern, CharSequence input, boolean withPattern) {
+ Matcher m = pattern.matcher(input);
+ int p = NO_MATCH;
+ if (m.find()) {
+ return withPattern ? m.end() : m.start();
+ }
+ return p;
+ }
+}
diff --git a/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/SyntaxHighlightFactory.java b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/SyntaxHighlightFactory.java
new file mode 100644
index 0000000..20c85dc
--- /dev/null
+++ b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/SyntaxHighlightFactory.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.filemanager.ash;
+
+import com.cyanogenmod.filemanager.ash.spi.PropertiesSyntaxHighlightProcessor;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A factory of <code>SyntaxHighlightProcessor</code> classes.
+ */
+public class SyntaxHighlightFactory {
+
+ private static SyntaxHighlightFactory sFactory;
+
+ private final ArrayList<SyntaxHighlightProcessor> mProcessors;
+
+ /**
+ * Constructor of <code>SyntaxHighlightFactory</code>
+ */
+ public SyntaxHighlightFactory() {
+ super();
+ this.mProcessors = new ArrayList<SyntaxHighlightProcessor>();
+ }
+
+ /**
+ * Method that returns the default highlight factory instance
+ *
+ * @param resolver A class for allow the processor to obtain resources
+ * @return SyntaxHighlightFactory The default syntax highlight factory
+ */
+ public static final synchronized SyntaxHighlightFactory getDefaultFactory(
+ ISyntaxHighlightResourcesResolver resolver) {
+ if (sFactory == null) {
+ sFactory = createDefaultFactory(resolver);
+ }
+ return sFactory;
+ }
+
+ /**
+ * Method that returns the syntax highlight processor that can handle the file
+ *
+ * @param file The file to process
+ * @return SyntaxHighlightProcessor The syntax highlight processor
+ */
+ public SyntaxHighlightProcessor getSyntaxHighlightProcessor(File file) {
+ int cc = this.mProcessors.size();
+ for (int i = 0; i < cc; i++) {
+ SyntaxHighlightProcessor processor = this.mProcessors.get(i);
+ if (processor.accept(file)) {
+ return processor;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Method that return all the available syntax highlight processors.
+ *
+ * @return List<SyntaxHighlightProcessor> the list available syntax highlight processors.
+ */
+ public List<SyntaxHighlightProcessor> getAvailableSyntaxHighlightProcessors() {
+ return new ArrayList<SyntaxHighlightProcessor>(this.mProcessors);
+ }
+
+ /**
+ * Method that create the default syntax highlight factory.
+ *
+ * @param resolver A class for allow the processor to obtain resources
+ * @return SyntaxHighlightFactory The default factory
+ */
+ private static SyntaxHighlightFactory createDefaultFactory(
+ ISyntaxHighlightResourcesResolver resolver) {
+ // TODO Read all processors classes of the SPI package
+ // For now we add all known syntax highlight processors
+ SyntaxHighlightFactory factory = new SyntaxHighlightFactory();
+ factory.mProcessors.add(new PropertiesSyntaxHighlightProcessor(resolver));
+ return factory;
+ }
+}
diff --git a/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/SyntaxHighlightProcessor.java b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/SyntaxHighlightProcessor.java
new file mode 100644
index 0000000..2d52034
--- /dev/null
+++ b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/SyntaxHighlightProcessor.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.filemanager.ash;
+
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.style.ForegroundColorSpan;
+
+import java.io.File;
+
+/**
+ * The base class for all the syntax highlight processors.</br>
+ */
+public abstract class SyntaxHighlightProcessor {
+
+ protected final ISyntaxHighlightResourcesResolver mResourcesResolver;
+
+ /**
+ * Constructor of <code>SyntaxHighlightProcessor</code>
+ *
+ * @param resolver A class for resolve resources
+ */
+ public SyntaxHighlightProcessor(ISyntaxHighlightResourcesResolver resolver) {
+ super();
+ this.mResourcesResolver = resolver;
+ }
+
+ /**
+ * Method that request to the syntax highlight processor if it is able to parse
+ * the file
+ *
+ * @param file The file to check
+ * @return boolean If the syntax highlight processor accepts process the file
+ */
+ protected abstract boolean accept(File file);
+
+ /**
+ * Method that initializes the processor
+ */
+ public abstract void initialize();
+
+ /**
+ * Method that request to the syntax highlight processor to do process and highlight a
+ * document. This method request a full process.
+ *
+ * @param spanable The spannable source to highlight
+ */
+ public abstract void process(Spannable spanable);
+
+ /**
+ * Method that request to the syntax highlight processor to process and highlight a
+ * document. This method request a partial process.
+ *
+ * @param spanable The spannable source to highlight
+ * @param start The start of spannable to process
+ * @param end The end of spannable to process
+ */
+ public abstract void process(Spannable spanable, int start, int end);
+
+ /**
+ * Method that cancels the active processor
+ */
+ public abstract void cancel();
+
+ /**
+ * Method that clear all the existent spans
+ *
+ * @param spanable The spannable
+ */
+ @SuppressWarnings("static-method")
+ public void clear(Spannable spanable) {
+ ForegroundColorSpan[] spans =
+ spanable.getSpans(0, spanable.length(), ForegroundColorSpan.class);
+ int cc = spans.length;
+ for (int i = 0; i < cc; i++) {
+ spanable.removeSpan(spans[i]);
+ }
+ }
+
+
+ /**
+ * Method that sets a new <code>Spannable</code>.
+ *
+ * @param spanable The spannable
+ * @param color The color of the span
+ * @param start The start of the span
+ * @param end The end of the span
+ */
+ @SuppressWarnings("static-method")
+ protected void setSpan(Spannable spanable, int color, int start, int end) {
+ if (start == end) return;
+ spanable.setSpan(
+ new ForegroundColorSpan(color),
+ start,
+ end,
+ Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+}
diff --git a/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/scanners/NewLineScanner.java b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/scanners/NewLineScanner.java
new file mode 100644
index 0000000..5552b8e
--- /dev/null
+++ b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/scanners/NewLineScanner.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.filemanager.ash.scanners;
+
+import java.util.regex.Matcher;
+
+import com.cyanogenmod.filemanager.ash.RegExpUtil;
+
+/**
+ * An scanner to process an input, reporting every text into new lines.
+ */
+public class NewLineScanner extends Scanner {
+
+ private final NewLineScannerListener mListener;
+
+ /**
+ * The listener for the newline scanner
+ */
+ public interface NewLineScannerListener {
+ /**
+ * When a new line is ready
+ *
+ * @param newline The newline detected
+ * @param start The start position of the new line within the input text
+ * @param end The end position of the new line within the input text
+ * @param sep The line separator detected
+ * @return boolean If processor must continue with the next line
+ */
+ boolean onNewLine(CharSequence newline, int start, int end, CharSequence sep);
+ }
+
+ /**
+ * Constructor of <code>Scanner</code>
+ *
+ * @param input The input
+ * @param listener The listener where return every new line
+ */
+ public NewLineScanner(CharSequence input, NewLineScannerListener listener) {
+ super(input);
+ this.mListener = listener;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void scan() {
+ if (this.mInput.length() == 0) return;
+ Matcher m = RegExpUtil.NEWLINE_PATTERN.matcher(this.mInput);
+ int next = 0;
+ while(m.find(next)) {
+ CharSequence line = this.mInput.subSequence(next, m.start());
+ if (!this.mListener.onNewLine(line, next, m.start(), m.group())) {
+ return;
+ }
+ next = m.end();
+ }
+ // The non-matched data
+ CharSequence line = this.mInput.subSequence(next, this.mInput.length());
+ this.mListener.onNewLine(line, next, this.mInput.length(), null);
+ }
+}
diff --git a/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/scanners/Scanner.java b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/scanners/Scanner.java
new file mode 100644
index 0000000..3158345
--- /dev/null
+++ b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/scanners/Scanner.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.cyanogenmod.filemanager.ash.scanners;
+
+
+/**
+ * The base class for all the scanners
+ */
+public abstract class Scanner {
+
+ CharSequence mInput;
+
+ /**
+ * Constructor of <code>Scanner</code>
+ *
+ * @param input The input
+ */
+ public Scanner(CharSequence input) {
+ super();
+ this.mInput = input;
+ }
+
+ /**
+ * Method that starts the scan process
+ */
+ public abstract void scan();
+}
diff --git a/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/spi/PropertiesSyntaxHighlightProcessor.java b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/spi/PropertiesSyntaxHighlightProcessor.java
new file mode 100644
index 0000000..f9fd19a
--- /dev/null
+++ b/libs/android-syntax-highlight/src/com/cyanogenmod/filemanager/ash/spi/PropertiesSyntaxHighlightProcessor.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2013 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyanogenmod.filemanager.ash.spi;
+
+import android.text.Spannable;
+import android.text.style.ForegroundColorSpan;
+
+import com.cyanogenmod.filemanager.ash.HighlightColors;
+import com.cyanogenmod.filemanager.ash.ISyntaxHighlightResourcesResolver;
+import com.cyanogenmod.filemanager.ash.RegExpUtil;
+import com.cyanogenmod.filemanager.ash.SyntaxHighlightProcessor;
+import com.cyanogenmod.filemanager.ash.scanners.NewLineScanner;
+import com.cyanogenmod.filemanager.ash.scanners.NewLineScanner.NewLineScannerListener;
+
+import java.io.File;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A <b>properties</b> highlight processor class.</br>
+ * </br>
+ * The behaviour of this class is:</br>
+ * <ul>
+ * <li>Comments start with # (only spaces are allowed prior to comment)</li>
+ * <li>Assignment character (=) separates key from value</li>
+ * <li>Arguments exists only in values, and are composed by {a digit}</li>
+ * <li>Values can be extended in multiple lines if line ends with the char "\". A
+ * comment in multiline breaks the multiline and starts a new property.</li>
+ * </ul>
+ * </br>
+ * IMP! This class is not thread safe. Calling "process" methods should be
+ * done in a synchronous way.
+ */
+public class PropertiesSyntaxHighlightProcessor extends SyntaxHighlightProcessor {
+
+ private static final String EXT_PROP = "prop"; //$NON-NLS-1$
+ private static final String EXT_PROPERTIES = "properties"; //$NON-NLS-1$
+
+ private static final Pattern COMMENT = Pattern.compile("^\\s*#.*"); //$NON-NLS-1$
+ private static final Pattern MULTILINE = Pattern.compile(".*\\\\\\s*$"); //$NON-NLS-1$
+ private static final Pattern ASSIGNMENT = Pattern.compile("="); //$NON-NLS-1$
+ private static final Pattern ARGUMENT = Pattern.compile("\\{\\d+\\}"); //$NON-NLS-1$
+
+ protected Spannable mSpannable;
+ private boolean mMultiLine;
+
+ private int mKeyColor;
+ private int mAssignmentColor;
+ private int mCommentColor;
+ private int mValueColor;
+ private int mArgumentColor;
+
+ /**
+ * Constructor of <code>PropertiesSyntaxHighlightProcessor</code>
+ *
+ * @param resolver A class for resolve resources
+ */
+ public PropertiesSyntaxHighlightProcessor(ISyntaxHighlightResourcesResolver resolver) {
+ super(resolver);
+ initialize();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean accept(File file) {
+ if (file == null) return false;
+ return file.getName().toLowerCase().endsWith(EXT_PROP) ||
+ file.getName().toLowerCase().endsWith(EXT_PROPERTIES);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initialize() {
+ this.mMultiLine = false;
+ this.mSpannable = null;
+ if (this.mResourcesResolver != null) {
+ this.mKeyColor = this.mResourcesResolver.getColor(
+ HighlightColors.TEXT.getId(),
+ HighlightColors.TEXT.getResId(),
+ HighlightColors.TEXT.getDefault());
+ this.mAssignmentColor = this.mResourcesResolver.getColor(
+ HighlightColors.ASSIGNMENT.getId(),
+ HighlightColors.ASSIGNMENT.getResId(),
+ HighlightColors.ASSIGNMENT.getDefault());
+ this.mCommentColor = this.mResourcesResolver.getColor(
+ HighlightColors.SINGLE_LINE_COMMENT.getId(),
+ HighlightColors.SINGLE_LINE_COMMENT.getResId(),
+ HighlightColors.SINGLE_LINE_COMMENT.getDefault());
+ this.mValueColor = this.mResourcesResolver.getColor(
+ HighlightColors.VARIABLE.getId(),
+ HighlightColors.VARIABLE.getResId(),
+ HighlightColors.VARIABLE.getDefault());
+ this.mArgumentColor = this.mResourcesResolver.getColor(
+ HighlightColors.KEYWORD.getId(),
+ HighlightColors.KEYWORD.getResId(),
+ HighlightColors.KEYWORD.getDefault());
+ } else {
+ // By default
+ this.mKeyColor = HighlightColors.TEXT.getDefault();
+ this.mAssignmentColor = HighlightColors.TEXT.getDefault();
+ this.mCommentColor = HighlightColors.SINGLE_LINE_COMMENT.getDefault();
+ this.mValueColor = HighlightColors.VARIABLE.getDefault();
+ this.mArgumentColor = HighlightColors.KEYWORD.getDefault();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void process(final Spannable spanable) {
+ this.mMultiLine = false;
+ this.mSpannable = spanable;
+ clear(spanable);
+ NewLineScanner scanner = new NewLineScanner(spanable, new NewLineScannerListener() {
+ @Override
+ public boolean onNewLine(CharSequence newline, int start, int end, CharSequence sep) {
+ processNewLine(newline, start, end);
+ return true;
+ }
+
+ });
+ scanner.scan();
+ this.mSpannable = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void process(final Spannable spanable, final int start, final int end) {
+ // We need a Retrieve the previous line
+ this.mMultiLine = false;
+ this.mSpannable = spanable;
+ CharSequence seqs = spanable.subSequence(0, start);
+ CharSequence seqe = spanable.subSequence(end, spanable.length());
+ int s1 = RegExpUtil.getLastMatch(RegExpUtil.NEWLINE_PATTERN, seqs, false);
+ if (s1 == RegExpUtil.NO_MATCH) {
+ s1 = 0;
+ }
+ int e1 = RegExpUtil.getNextMatch(RegExpUtil.NEWLINE_PATTERN, seqe, false);
+ if (e1 == RegExpUtil.NO_MATCH) {
+ e1 = spanable.length();
+ } else {
+ e1 += end;
+ }
+
+ // Also, we need to know about if the previous line is multiline
+ if (s1 > 0) {
+ int s2 = RegExpUtil.getLastMatch(RegExpUtil.NEWLINE_PATTERN, seqs, true);
+ CharSequence seqnl = spanable.subSequence(0, s2);
+ int snl = RegExpUtil.getLastMatch(RegExpUtil.NEWLINE_PATTERN, seqnl, false);
+ Matcher mlm = MULTILINE.matcher(
+ spanable.subSequence(snl != RegExpUtil.NO_MATCH ? snl : 0, s2));
+ this.mMultiLine = mlm.matches();
+ }
+
+ // Process the new line
+ if (s1 != e1) {
+ processNewLine(spanable.subSequence(s1, e1), s1, e1);
+ }
+
+ // Now, multiline again (next line). We check always the next line, because we
+ // don't know if user delete multiline flag in the current line
+ e1 = RegExpUtil.getNextMatch(RegExpUtil.NEWLINE_PATTERN, seqe, true);
+ if (e1 != RegExpUtil.NO_MATCH) {
+ e1 += end;
+ seqe = spanable.subSequence(e1, spanable.length());
+ int e2 = RegExpUtil.getNextMatch(RegExpUtil.NEWLINE_PATTERN, seqe, false);
+ if (e2 == RegExpUtil.NO_MATCH) {
+ e2 = spanable.length();
+ } else {
+ e2 += e1;
+ }
+ processNewLine(spanable.subSequence(e1, e2), e1, e2);
+ }
+
+ this.mSpannable = null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void cancel() {
+ // Not needed by this processor
+ }
+
+ /**
+ * A method to process every new line
+ *
+ * @param newline The newline
+ * @param start The start position of the line
+ * @param end The end position of the line
+ * @hide
+ */
+ void processNewLine(CharSequence newline, int start, int end) {
+ // Remove all spannable of the line (this processor doesn't multiline spans and
+ // only uses ForegroundColorSpan spans)
+ ForegroundColorSpan[] spans =
+ this.mSpannable.getSpans(start, end, ForegroundColorSpan.class);
+ int cc = spans.length;
+ for (int i = 0; i < cc; i++) {
+ this.mSpannable.removeSpan(spans[i]);
+ }
+
+ // Find comment
+ Matcher cm = COMMENT.matcher(newline);
+ if (cm.matches()) {
+ // All the line is a comment
+ setSpan(this.mSpannable, this.mCommentColor, start, end);
+ this.mMultiLine = false;
+ return;
+ }
+
+ // Has multiline
+ Matcher mlm = MULTILINE.matcher(newline);
+ boolean ml = mlm.matches();
+
+ //Find the assignment
+ int k = this.mMultiLine ? -1 : start;
+ int v = start;
+ int v2 = 0;
+ int a = -1;
+ if (!this.mMultiLine) {
+ Matcher am = ASSIGNMENT.matcher(newline);
+ if (am.find()) {
+ // Assignment found
+ v2 = am.start() + 1;
+ a = start + am.start();
+ v = a + 1;
+ }
+ }
+
+ // All the string is a key
+ if (!this.mMultiLine && a == -1) {
+ setSpan(this.mSpannable, this.mKeyColor, start, end);
+
+ } else {
+ // Key
+ if (!this.mMultiLine) {
+ setSpan(this.mSpannable, this.mKeyColor, k, a);
+ }
+ // Assignment
+ if (!this.mMultiLine) {
+ setSpan(this.mSpannable, this.mAssignmentColor, a, a + 1);
+ }
+ // Value
+ setSpan(this.mSpannable, this.mValueColor, v, end);
+ // Argument
+ Matcher argm = ARGUMENT.matcher(newline);
+ while (argm.find(v2)) {
+ int s = start + argm.start();
+ int e = start + argm.end();
+ setSpan(this.mSpannable, this.mArgumentColor, s, e);
+ v2 = argm.end();
+ }
+ }
+
+ // Multiline?
+ this.mMultiLine = ml;
+ }
+}