From 2cd1717e9777854dbe8402d4d711631c181f7357 Mon Sep 17 00:00:00 2001 From: Manhal Jasem Date: Sat, 14 Dec 2024 02:51:15 +0100 Subject: [PATCH 01/14] HansTrafficLight added without functionality --- .../trafficLight/HansTrafficLightAction.java | 59 +++++++ .../HansTrafficLightActionProvider.java | 23 +++ .../trafficLight/HansTrafficLightWidget.java | 155 ++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 1 + 4 files changed, 238 insertions(+) create mode 100644 src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java create mode 100644 src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java create mode 100644 src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java new file mode 100644 index 00000000..5e4688a5 --- /dev/null +++ b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java @@ -0,0 +1,59 @@ +package se.isselab.HAnS.trafficLight; + +import com.intellij.openapi.actionSystem.ActionUpdateThread; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.ex.CustomComponentAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.DumbAware; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +public class HansTrafficLightAction extends AnAction implements DumbAware, CustomComponentAction { + private Editor editor; + HansTrafficLightAction() { + super(); + } + HansTrafficLightAction(Editor editor) { + this.editor = editor; + } + + @Override + public @NotNull JComponent createCustomComponent(@NotNull Presentation presentation, @NotNull String place) { + return new HansTrafficLightWidget(this, presentation, place, editor); + } + + @Override + public void updateCustomComponent(@NotNull JComponent component, @NotNull Presentation presentation) { + CustomComponentAction.super.updateCustomComponent(component, presentation); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent anActionEvent) { + + } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.BGT; + } + + @Override + public final void update(AnActionEvent e) { + var p = e.getProject(); + if (p == null || !p.isInitialized() || p.isDisposed()) { + e.getPresentation().setEnabledAndVisible(false); + return; + } + var visible = e.getPresentation().isVisible(); + e.getPresentation().setVisible(visible); + if (!visible) { + e.getPresentation().setEnabled(false); + return; + } + + e.getPresentation().setEnabled(true); + } +} diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java new file mode 100644 index 00000000..e03f88ed --- /dev/null +++ b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java @@ -0,0 +1,23 @@ +package se.isselab.HAnS.trafficLight; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.DefaultActionGroup; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorKind; +import com.intellij.openapi.actionSystem.Separator; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.markup.InspectionWidgetActionProvider; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class HansTrafficLightActionProvider implements InspectionWidgetActionProvider { + + @Override + public @Nullable AnAction createAction(@NotNull Editor editor) { + if (editor.getEditorKind() == EditorKind.MAIN_EDITOR) { + return new DefaultActionGroup(new HansTrafficLightAction(editor), Separator.create()); + } + return null; + } +} diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java new file mode 100644 index 00000000..911aaa7b --- /dev/null +++ b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java @@ -0,0 +1,155 @@ +package se.isselab.HAnS.trafficLight; + +import com.intellij.openapi.actionSystem.ActionToolbar; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.openapi.actionSystem.ex.ActionButtonLook; +import com.intellij.openapi.actionSystem.ex.ActionUtil; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.colors.ColorKey; +import com.intellij.openapi.editor.ex.util.EditorUtil; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.SystemInfo; +import com.intellij.ui.JBColor; +import com.intellij.ui.scale.JBUIScale; +import com.intellij.util.ui.JBInsets; +import com.intellij.util.ui.JBUI; +import com.intellij.util.ui.UIUtil; +import se.isselab.HAnS.AnnotationIcons; +import com.intellij.openapi.actionSystem.ActionButtonComponent; +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.plaf.FontUIResource; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.util.Objects; + +public class HansTrafficLightWidget extends JPanel { + private AnAction action; + private Presentation presentation; + private MouseListener mouseListener; + private boolean mousePressed = false; + private boolean mouseHover = false; + private JLabel hansIcon; + private Editor editor; + private String place; + + HansTrafficLightWidget(AnAction action, Presentation presentation, + String place, Editor editor){ + setOpaque(false); + + hansIcon = new JLabel(); + + if (!SystemInfo.isWindows) { + hansIcon.setFont(new FontUIResource(getFont().deriveFont(getFont().getStyle(), + (float) (getFont().getSize() - JBUIScale.scale(2))))); + } + + hansIcon.setForeground(new JBColor( + Objects.requireNonNull(editor.getColorsScheme().getColor(ColorKey.createColorKey("ActionButton.iconTextForeground", + UIUtil.getContextHelpForeground()))), + ColorKey.createColorKey("ActionButton.iconTextForeground", UIUtil.getContextHelpForeground()).getDefaultColor() + )); + + hansIcon.setIcon(AnnotationIcons.PluginIcon); + + hansIcon.setVisible(false); + + add(hansIcon); + + + + mouseListener = new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + mousePressed = true; + repaint(); + + } + + @Override + public void mouseReleased(MouseEvent e) { + var context = ActionToolbar.getDataContextFor(HansTrafficLightWidget.this); + var event = AnActionEvent.createFromInputEvent(e, place, presentation, context, false, true); + ActionUtil.performActionDumbAwareWithCallbacks(action, event); + mousePressed = false; + repaint(); + openMappingsFile(); + } + + @Override + public void mouseEntered(MouseEvent e) { + mouseHover = true; + repaint(); + showPopupWithMappingName(); + } + + @Override + public void mouseExited(MouseEvent e) { + mouseHover = false; + repaint(); + } + }; + + setBorder(new Border() { + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + // Empty border + } + + @Override + public Insets getBorderInsets(Component c) { + return JBUI.insets(0, 2); + } + + @Override + public boolean isBorderOpaque() { + return false; + } + }); + + if (editor.getProject() != null) { + var disposable = Disposer.newDisposable(); + EditorUtil.disposeWithEditor(editor, disposable); + } + + } + + @Override + public void removeNotify() { + removeMouseListener(mouseListener); + } + + @Override + public void addNotify() { + super.addNotify(); + addMouseListener(mouseListener); + } + + private void showPopupWithMappingName() { + } + + private void openMappingsFile() { + + } + + @Override + protected void paintComponent(Graphics graphics) { + int state = mousePressed ? ActionButtonComponent.PUSHED + : mouseHover ? ActionButtonComponent.POPPED + : ActionButtonComponent.NORMAL; + if (state == ActionButtonComponent.NORMAL) return; + + var rect = new Rectangle(getSize()); + JBInsets.removeFrom(rect, JBUI.insets(2)); + + Color color = (state == ActionButtonComponent.PUSHED) + ? JBUI.CurrentTheme.ActionButton.pressedBackground() + : JBUI.CurrentTheme.ActionButton.hoverBackground(); + + ActionButtonLook.SYSTEM_LOOK.paintLookBackground(graphics, rect, color); + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index f755552b..419d46db 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -130,6 +130,7 @@ limitations under the License. + From eb1fdb6bb0fb540898bb04045627c420c89d6f3e Mon Sep 17 00:00:00 2001 From: Manhal Jasem Date: Tue, 17 Dec 2024 01:23:23 +0100 Subject: [PATCH 02/14] HansTrafficLight added functionality --- .../featureLocation/FeatureFileMapping.java | 13 ++++ .../trafficLight/HansTrafficLightWidget.java | 77 +++++++++++++++++-- 2 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java b/src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java index 85725710..f46dba08 100644 --- a/src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java +++ b/src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java @@ -203,6 +203,19 @@ public Set> getMappedPathPair() { return map.keySet(); } + public Set getFileMappings() { + + var keys = map.keySet(); + Set result = new HashSet<>(); + + for (var key: keys) { + var val = map.get(key); + if (val.first.name().equals("FILE") || val.first.name().equals("FOLDER")) { + result.add(key.first + ":" + key.second); + } + } + return result; + } // &begin[LineCount] /** diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java index 911aaa7b..2c7a8a4e 100644 --- a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java +++ b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java @@ -1,23 +1,34 @@ package se.isselab.HAnS.trafficLight; -import com.intellij.openapi.actionSystem.ActionToolbar; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.ActionButtonLook; import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.colors.ColorKey; import com.intellij.openapi.editor.ex.util.EditorUtil; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.JBColor; import com.intellij.ui.scale.JBUIScale; import com.intellij.util.ui.JBInsets; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; +import kotlinx.html.P; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import se.isselab.HAnS.AnnotationIcons; -import com.intellij.openapi.actionSystem.ActionButtonComponent; +import se.isselab.HAnS.featureLocation.FeatureFileMapping; +import se.isselab.HAnS.featureModel.psi.FeatureModelFeature; +import se.isselab.HAnS.pluginExtensions.backgroundTasks.featureFileMappingTasks.FeatureFileMappingCallback; +import se.isselab.HAnS.pluginExtensions.backgroundTasks.featureFileMappingTasks.GetFeatureFileMappings; + import javax.swing.*; import javax.swing.border.Border; import javax.swing.plaf.FontUIResource; @@ -25,7 +36,11 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.io.File; +import java.util.HashSet; +import java.util.Map; import java.util.Objects; +import java.util.Set; public class HansTrafficLightWidget extends JPanel { private AnAction action; @@ -36,9 +51,14 @@ public class HansTrafficLightWidget extends JPanel { private JLabel hansIcon; private Editor editor; private String place; + private String filePath; HansTrafficLightWidget(AnAction action, Presentation presentation, String place, Editor editor){ + this.action = action; + this.presentation = presentation; + this.place = place; + this.editor = editor; setOpaque(false); hansIcon = new JLabel(); @@ -58,9 +78,9 @@ public class HansTrafficLightWidget extends JPanel { hansIcon.setVisible(false); - add(hansIcon); - + searchFeatures(); + add(hansIcon); mouseListener = new MouseAdapter() { @Override @@ -118,6 +138,29 @@ public boolean isBorderOpaque() { } + private void searchFeatures() { + new GetFeatureFileMappings(this.editor.getProject(), "Find Feature File Mappings", new FeatureFileMappingCallback() { + @Override + public void onComplete(Map featureFileMappings) { + Set> vals = new HashSet<>(); + featureFileMappings.forEach((key, value) -> { + var res = value.getFileMappings(); + if (!res.isEmpty()) { + vals.add(res); + } + }); + for (Set val : vals) { + for (String key : val) { + if (key.contains(editor.getVirtualFile().getPath())){ + filePath = key.substring(key.indexOf(":")+1); + hansIcon.setVisible(true); + } + } + } + } + }).queue(); + } + @Override public void removeNotify() { removeMouseListener(mouseListener); @@ -129,15 +172,33 @@ public void addNotify() { addMouseListener(mouseListener); } + public String getFilePath() { + return filePath; + } + private void showPopupWithMappingName() { + Notification notification = new Notification( + "notification", // Notification Group ID (can be created as needed) + "Mapped feature file", // Title + filePath, // Content + NotificationType.INFORMATION // Type: INFORMATION, WARNING, or ERROR + ); + Notifications.Bus.notify(notification); } private void openMappingsFile() { - + VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(filePath)); + if (virtualFile != null && this.editor.getProject() != null) { + // Open the file in the editor + FileEditorManager.getInstance(this.editor.getProject()).openFile(virtualFile, true); + } else { + JOptionPane.showMessageDialog(null, "File not found: " + filePath); + } } @Override protected void paintComponent(Graphics graphics) { + if (filePath == null) return; int state = mousePressed ? ActionButtonComponent.PUSHED : mouseHover ? ActionButtonComponent.POPPED : ActionButtonComponent.NORMAL; From ab98dc01aae3a4f48ceb9316c8988e0229dd27d7 Mon Sep 17 00:00:00 2001 From: Manhal Jasem Date: Thu, 16 Jan 2025 07:49:16 +0100 Subject: [PATCH 03/14] HansTrafficLight added functionality 1 --- .../trafficLight/HansTrafficLightWidget.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java index 2c7a8a4e..97ef1d1f 100644 --- a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java +++ b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java @@ -86,7 +86,9 @@ public class HansTrafficLightWidget extends JPanel { @Override public void mousePressed(MouseEvent e) { mousePressed = true; - repaint(); + if (hansIcon.isVisible()) { + repaint(); + } } @@ -96,21 +98,28 @@ public void mouseReleased(MouseEvent e) { var event = AnActionEvent.createFromInputEvent(e, place, presentation, context, false, true); ActionUtil.performActionDumbAwareWithCallbacks(action, event); mousePressed = false; - repaint(); - openMappingsFile(); + if (hansIcon.isVisible()) { + repaint(); + openMappingsFile(); + } } @Override public void mouseEntered(MouseEvent e) { mouseHover = true; - repaint(); - showPopupWithMappingName(); + if (hansIcon.isVisible()){ + repaint(); + showPopupWithMappingName(); + } + } @Override public void mouseExited(MouseEvent e) { mouseHover = false; - repaint(); + if (hansIcon.isVisible()){ + repaint(); + } } }; @@ -172,16 +181,12 @@ public void addNotify() { addMouseListener(mouseListener); } - public String getFilePath() { - return filePath; - } - private void showPopupWithMappingName() { Notification notification = new Notification( - "notification", // Notification Group ID (can be created as needed) - "Mapped feature file", // Title - filePath, // Content - NotificationType.INFORMATION // Type: INFORMATION, WARNING, or ERROR + "notification", + "Mapped feature file", + filePath, + NotificationType.INFORMATION ); Notifications.Bus.notify(notification); } @@ -189,7 +194,6 @@ private void showPopupWithMappingName() { private void openMappingsFile() { VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(filePath)); if (virtualFile != null && this.editor.getProject() != null) { - // Open the file in the editor FileEditorManager.getInstance(this.editor.getProject()).openFile(virtualFile, true); } else { JOptionPane.showMessageDialog(null, "File not found: " + filePath); From 3509eaa7d4b017aeb460cc947a8fe6cec31ff590 Mon Sep 17 00:00:00 2001 From: Manhal Jasem Date: Wed, 5 Feb 2025 16:20:25 +0100 Subject: [PATCH 04/14] Optionally in the language model added --- .../FeatureModelHighlightingLexer.java | 204 +++++++++----- .../HAnS/featureModel/FeatureModelLexer.java | 261 +++++++++++------- .../parser/FeatureModelParser.java | 67 ++++- .../featureModel/psi/FeatureModelOrGroup.java | 13 + .../featureModel/psi/FeatureModelTypes.java | 5 + .../featureModel/psi/FeatureModelVisitor.java | 4 + .../psi/impl/FeatureModelOrGroupImpl.java | 36 +++ .../HAnS/featureModel/FeatureModel.bnf | 3 +- .../HAnS/featureModel/FeatureModel.flex | 4 +- 9 files changed, 417 insertions(+), 180 deletions(-) create mode 100644 src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelOrGroup.java create mode 100644 src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelOrGroupImpl.java diff --git a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelHighlightingLexer.java b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelHighlightingLexer.java index 6891649e..b8c8496c 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelHighlightingLexer.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelHighlightingLexer.java @@ -1,18 +1,29 @@ -/* The following code was generated by JFlex 1.7.0 tweaked for IntelliJ platform */ +// Generated by JFlex 1.9.2 http://jflex.de/ (tweaked for IntelliJ platform) +// source: FeatureModelHighlightingLexer.flex +/* +Copyright 2021 Herman Jansson & Johan Martinson + +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 + + https://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 se.isselab.HAnS.featureModel; +import com.intellij.lexer.FlexLexer; import com.intellij.psi.tree.IElementType; import se.isselab.HAnS.featureModel.psi.FeatureModelTypes; -import com.intellij.lexer.FlexLexer; import com.intellij.psi.TokenType; -/** - * This class is a scanner generated by - * JFlex 1.7.0 - * from the specification file FeatureModelHighlightingLexer.flex - */ public class FeatureModelHighlightingLexer implements FlexLexer { /** This character denotes the end of file */ @@ -31,33 +42,68 @@ public class FeatureModelHighlightingLexer implements FlexLexer { * at the beginning of a line * l is of the form l = 2*k, k a non negative integer */ - private static final int ZZ_LEXSTATE[] = { + private static final int ZZ_LEXSTATE[] = { 0, 0, 1, 1 }; - /** - * Translates characters to character classes - * Chosen bits are [8, 6, 7] - * Total runtime size is 1040 bytes + /** + * Top-level table for translating characters to character classes */ - public static int ZZ_CMAP(int ch) { - return ZZ_CMAP_A[ZZ_CMAP_Y[ZZ_CMAP_Z[ch>>13]|((ch>>7)&0x3f)]|(ch&0x7f)]; + private static final int [] ZZ_CMAP_TOP = zzUnpackcmap_top(); + + private static final String ZZ_CMAP_TOP_PACKED_0 = + "\1\0\u10ff\u0100"; + + private static int [] zzUnpackcmap_top() { + int [] result = new int[4352]; + int offset = 0; + offset = zzUnpackcmap_top(ZZ_CMAP_TOP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackcmap_top(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; } - /* The ZZ_CMAP_Z table has 136 entries */ - static final char ZZ_CMAP_Z[] = zzUnpackCMap( - "\1\0\207\100"); - /* The ZZ_CMAP_Y table has 128 entries */ - static final char ZZ_CMAP_Y[] = zzUnpackCMap( - "\1\0\177\200"); + /** + * Second-level tables for translating characters to character classes + */ + private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks(); + + private static final String ZZ_CMAP_BLOCKS_PACKED_0 = + "\11\0\1\1\1\2\2\0\1\2\22\0\1\1\6\0"+ + "\1\3\3\0\1\4\4\0\12\4\7\0\32\4\4\0"+ + "\1\4\1\0\32\4\1\0\1\5\u0183\0"; + + private static int [] zzUnpackcmap_blocks() { + int [] result = new int[512]; + int offset = 0; + offset = zzUnpackcmap_blocks(ZZ_CMAP_BLOCKS_PACKED_0, offset, result); + return result; + } - /* The ZZ_CMAP_A table has 256 entries */ - static final char ZZ_CMAP_A[] = zzUnpackCMap( - "\11\0\1\2\1\1\2\0\1\1\22\0\1\2\6\0\1\5\3\0\1\3\4\0\12\3\7\0\32\3\4\0\1\3\1"+ - "\0\32\3\1\0\1\4\203\0"); + private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } - /** + /** * Translates DFA states to action switch labels. */ private static final int [] ZZ_ACTION = zzUnpackAction(); @@ -85,7 +131,7 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { } - /** + /** * Translates a state to a row index in the transition table */ private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); @@ -103,7 +149,7 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { private static int zzUnpackRowMap(String packed, int offset, int [] result) { int i = 0; /* index in packed string */ int j = offset; /* index in unpacked array */ - int l = packed.length(); + int l = packed.length() - 1; while (i < l) { int high = packed.charAt(i++) << 16; result[j++] = high | packed.charAt(i++); @@ -111,25 +157,25 @@ private static int zzUnpackRowMap(String packed, int offset, int [] result) { return j; } - /** + /** * The transition table of the DFA */ - private static final int [] ZZ_TRANS = zzUnpackTrans(); + private static final int [] ZZ_TRANS = zzUnpacktrans(); private static final String ZZ_TRANS_PACKED_0 = "\1\3\1\4\1\5\1\6\1\7\1\10\1\3\1\4"+ - "\1\5\1\3\1\4\1\5\7\0\1\4\2\0\1\4"+ - "\3\0\1\5\2\0\1\5\3\0\3\6\1\0\1\4"+ - "\1\0\1\6\1\7\1\6\2\0\1\5\2\6\1\10"; + "\1\5\1\4\1\3\1\5\7\0\1\4\1\0\1\4"+ + "\4\0\1\5\2\0\1\5\1\0\1\4\1\0\1\6"+ + "\2\7\3\0\3\7\2\0\1\5\2\7\1\10"; - private static int [] zzUnpackTrans() { + private static int [] zzUnpacktrans() { int [] result = new int[48]; int offset = 0; - offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + offset = zzUnpacktrans(ZZ_TRANS_PACKED_0, offset, result); return result; } - private static int zzUnpackTrans(String packed, int offset, int [] result) { + private static int zzUnpacktrans(String packed, int offset, int [] result) { int i = 0; /* index in packed string */ int j = offset; /* index in unpacked array */ int l = packed.length(); @@ -156,7 +202,7 @@ private static int zzUnpackTrans(String packed, int offset, int [] result) { }; /** - * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + * ZZ_ATTRIBUTE[aState] contains the attributes of state {@code aState} */ private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); @@ -219,6 +265,19 @@ the source of the yytext() string */ /** denotes if the user-EOF-code has already been executed */ private boolean zzEOFDone; + /** Number of newlines encountered up to the start of the matched text. */ + @SuppressWarnings("unused") + private int yyline; + + /** Number of characters from the last newline up to the start of the matched text. */ + @SuppressWarnings("unused") + protected int yycolumn; + + /** Number of characters up to the start of the matched text. */ + @SuppressWarnings("unused") + private long yychar; + + /** * Creates a new scanner @@ -230,26 +289,22 @@ public FeatureModelHighlightingLexer(java.io.Reader in) { } - /** - * Unpacks the compressed character translation table. - * - * @param packed the packed character translation table - * @return the unpacked character translation table + /** Returns the maximum size of the scanner buffer, which limits the size of tokens. */ + private int zzMaxBufferLen() { + return Integer.MAX_VALUE; + } + + /** Whether the scanner buffer can grow to accommodate a larger token. */ + private boolean zzCanGrow() { + return true; + } + + /** + * Translates raw input code points to DFA table row */ - private static char [] zzUnpackCMap(String packed) { - int size = 0; - for (int i = 0, length = packed.length(); i < length; i += 2) { - size += packed.charAt(i); - } - char[] map = new char[size]; - int i = 0; /* index in packed string */ - int j = 0; /* index in unpacked array */ - while (i < packed.length()) { - int count = packed.charAt(i++); - char value = packed.charAt(i++); - do map[j++] = value; while (--count > 0); - } - return map; + private static int zzCMap(int input) { + int offset = input & 255; + return offset == input ? ZZ_CMAP_BLOCKS[offset] : ZZ_CMAP_BLOCKS[ZZ_CMAP_TOP[input >> 8] | offset]; } public final int getTokenStart() { @@ -393,7 +448,8 @@ private void zzDoEOF() { * @return the next token * @exception java.io.IOException if any I/O-Error occurs */ - public IElementType advance() throws java.io.IOException { + public IElementType advance() throws java.io.IOException + { int zzInput; int zzAction; @@ -427,7 +483,7 @@ public IElementType advance() throws java.io.IOException { while (true) { if (zzCurrentPosL < zzEndReadL) { - zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL); zzCurrentPosL += Character.charCount(zzInput); } else if (zzAtEOF) { @@ -449,11 +505,11 @@ else if (zzAtEOF) { break zzForAction; } else { - zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL); zzCurrentPosL += Character.charCount(zzInput); } } - int zzNext = zzTransL[ zzRowMapL[zzState] + ZZ_CMAP(zzInput) ]; + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMap(zzInput) ]; if (zzNext == -1) break zzForAction; zzState = zzNext; @@ -472,30 +528,30 @@ else if (zzAtEOF) { if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; - zzDoEOF(); + zzDoEOF(); return null; } else { switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 1: + case 1: { return TokenType.BAD_CHARACTER; - } - // fall through + } + // fall through case 5: break; - case 2: - { yybegin(YYINITIAL); return FeatureModelTypes.CRLF; - } - // fall through - case 6: break; - case 3: + case 2: { yybegin(YYINITIAL); return FeatureModelTypes.INDENT; - } - // fall through + } + // fall through + case 6: break; + case 3: + { yybegin(YYINITIAL); return FeatureModelTypes.CRLF; + } + // fall through case 7: break; - case 4: + case 4: { yybegin(YYINITIAL); return FeatureModelTypes.FEATURENAME; - } - // fall through + } + // fall through case 8: break; default: zzScanError(ZZ_NO_MATCH); diff --git a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java index fab5fb9a..f116f4b8 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java @@ -1,20 +1,31 @@ -/* The following code was generated by JFlex 1.7.0 tweaked for IntelliJ platform */ +// Generated by JFlex 1.9.2 http://jflex.de/ (tweaked for IntelliJ platform) +// source: FeatureModel.flex +/* +Copyright 2021 Herman Jansson & Johan Martinson + +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 + + https://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 se.isselab.HAnS.featureModel; +import com.intellij.lexer.FlexLexer; import com.intellij.psi.tree.IElementType; import se.isselab.HAnS.featureModel.psi.FeatureModelTypes; -import com.intellij.lexer.FlexLexer; import com.intellij.psi.TokenType; import java.util.ArrayDeque; import java.util.Deque; -/** - * This class is a scanner generated by - * JFlex 1.7.0 - * from the specification file FeatureModel.flex - */ public class FeatureModelLexer implements FlexLexer { /** This character denotes the end of file */ @@ -35,43 +46,79 @@ public class FeatureModelLexer implements FlexLexer { * at the beginning of a line * l is of the form l = 2*k, k a non negative integer */ - private static final int ZZ_LEXSTATE[] = { + private static final int ZZ_LEXSTATE[] = { 0, 0, 1, 1, 2, 2, 3, 3 }; - /** - * Translates characters to character classes - * Chosen bits are [9, 6, 6] - * Total runtime size is 1568 bytes + /** + * Top-level table for translating characters to character classes */ - public static int ZZ_CMAP(int ch) { - return ZZ_CMAP_A[(ZZ_CMAP_Y[ZZ_CMAP_Z[ch>>12]|((ch>>6)&0x3f)]<<6)|(ch&0x3f)]; + private static final int [] ZZ_CMAP_TOP = zzUnpackcmap_top(); + + private static final String ZZ_CMAP_TOP_PACKED_0 = + "\1\0\37\u0100\1\u0200\267\u0100\10\u0300\u1020\u0100"; + + private static int [] zzUnpackcmap_top() { + int [] result = new int[4352]; + int offset = 0; + offset = zzUnpackcmap_top(ZZ_CMAP_TOP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackcmap_top(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; } - /* The ZZ_CMAP_Z table has 272 entries */ - static final char ZZ_CMAP_Z[] = zzUnpackCMap( - "\1\0\1\100\1\200\u010d\100"); - /* The ZZ_CMAP_Y table has 192 entries */ - static final char ZZ_CMAP_Y[] = zzUnpackCMap( - "\1\0\1\1\1\2\175\3\1\4\77\3"); + /** + * Second-level tables for translating characters to character classes + */ + private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks(); + + private static final String ZZ_CMAP_BLOCKS_PACKED_0 = + "\11\0\1\1\1\2\2\3\1\2\22\0\1\4\6\0"+ + "\1\5\3\0\1\6\4\0\12\6\5\0\1\7\1\0"+ + "\32\6\4\0\1\6\1\0\32\6\1\0\1\10\10\0"+ + "\1\3\u01a2\0\2\3\326\0\u0100\3"; + + private static int [] zzUnpackcmap_blocks() { + int [] result = new int[1024]; + int offset = 0; + offset = zzUnpackcmap_blocks(ZZ_CMAP_BLOCKS_PACKED_0, offset, result); + return result; + } - /* The ZZ_CMAP_A table has 320 entries */ - static final char ZZ_CMAP_A[] = zzUnpackCMap( - "\11\0\1\3\1\1\2\7\1\1\22\0\1\2\6\0\1\6\3\0\1\4\4\0\12\4\7\0\32\4\4\0\1\4\1"+ - "\0\32\4\1\0\1\5\10\0\1\7\242\0\2\7\26\0"); + private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } - /** + /** * Translates DFA states to action switch labels. */ private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = "\4\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7"+ - "\1\10"; + "\1\10\1\0\2\7"; private static int [] zzUnpackAction() { - int [] result = new int[12]; + int [] result = new int[15]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -90,17 +137,17 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { } - /** + /** * Translates a state to a row index in the transition table */ private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\10\0\20\0\30\0\40\0\40\0\50\0\40"+ - "\0\40\0\40\0\60\0\40"; + "\0\0\0\11\0\22\0\33\0\44\0\44\0\44\0\55"+ + "\0\44\0\44\0\66\0\44\0\77\0\110\0\44"; private static int [] zzUnpackRowMap() { - int [] result = new int[12]; + int [] result = new int[15]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -109,7 +156,7 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { private static int zzUnpackRowMap(String packed, int offset, int [] result) { int i = 0; /* index in packed string */ int j = offset; /* index in unpacked array */ - int l = packed.length(); + int l = packed.length() - 1; while (i < l) { int high = packed.charAt(i++) << 16; result[j++] = high | packed.charAt(i++); @@ -117,25 +164,26 @@ private static int zzUnpackRowMap(String packed, int offset, int [] result) { return j; } - /** + /** * The transition table of the DFA */ - private static final int [] ZZ_TRANS = zzUnpackTrans(); + private static final int [] ZZ_TRANS = zzUnpacktrans(); private static final String ZZ_TRANS_PACKED_0 = - "\1\5\1\6\5\5\1\6\1\0\1\7\1\10\1\11"+ - "\1\12\1\7\1\10\1\0\4\6\3\13\1\6\1\14"+ - "\1\6\5\14\1\6\11\0\1\7\3\0\1\7\6\0"+ - "\3\13\1\0"; - - private static int [] zzUnpackTrans() { - int [] result = new int[56]; + "\2\5\2\6\5\5\1\0\1\7\1\10\1\0\2\11"+ + "\1\12\1\0\1\10\5\6\2\13\1\6\1\13\2\14"+ + "\2\6\5\14\13\0\1\10\5\0\1\10\4\0\1\15"+ + "\1\16\1\13\1\0\1\13\7\0\1\17\5\0\1\15"+ + "\1\16\1\13\1\17\1\13"; + + private static int [] zzUnpacktrans() { + int [] result = new int[81]; int offset = 0; - offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + offset = zzUnpacktrans(ZZ_TRANS_PACKED_0, offset, result); return result; } - private static int zzUnpackTrans(String packed, int offset, int [] result) { + private static int zzUnpacktrans(String packed, int offset, int [] result) { int i = 0; /* index in packed string */ int j = offset; /* index in unpacked array */ int l = packed.length(); @@ -162,15 +210,16 @@ private static int zzUnpackTrans(String packed, int offset, int [] result) { }; /** - * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + * ZZ_ATTRIBUTE[aState] contains the attributes of state {@code aState} */ private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\4\0\2\11\1\1\3\11\1\1\1\11"; + "\4\0\3\11\1\1\2\11\1\1\1\11\1\0\1\1"+ + "\1\11"; private static int [] zzUnpackAttribute() { - int [] result = new int[12]; + int [] result = new int[15]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -225,6 +274,19 @@ the source of the yytext() string */ /** denotes if the user-EOF-code has already been executed */ private boolean zzEOFDone; + /** Number of newlines encountered up to the start of the matched text. */ + @SuppressWarnings("unused") + private int yyline; + + /** Number of characters from the last newline up to the start of the matched text. */ + @SuppressWarnings("unused") + protected int yycolumn; + + /** Number of characters up to the start of the matched text. */ + @SuppressWarnings("unused") + private long yychar; + + /* user code: */ int current_line_indent = 0; int indent_level = 0; @@ -247,26 +309,22 @@ public FeatureModelLexer(java.io.Reader in) { } - /** - * Unpacks the compressed character translation table. - * - * @param packed the packed character translation table - * @return the unpacked character translation table + /** Returns the maximum size of the scanner buffer, which limits the size of tokens. */ + private int zzMaxBufferLen() { + return Integer.MAX_VALUE; + } + + /** Whether the scanner buffer can grow to accommodate a larger token. */ + private boolean zzCanGrow() { + return true; + } + + /** + * Translates raw input code points to DFA table row */ - private static char [] zzUnpackCMap(String packed) { - int size = 0; - for (int i = 0, length = packed.length(); i < length; i += 2) { - size += packed.charAt(i); - } - char[] map = new char[size]; - int i = 0; /* index in packed string */ - int j = 0; /* index in unpacked array */ - while (i < packed.length()) { - int count = packed.charAt(i++); - char value = packed.charAt(i++); - do map[j++] = value; while (--count > 0); - } - return map; + private static int zzCMap(int input) { + int offset = input & 255; + return offset == input ? ZZ_CMAP_BLOCKS[offset] : ZZ_CMAP_BLOCKS[ZZ_CMAP_TOP[input >> 8] | offset]; } public final int getTokenStart() { @@ -398,8 +456,8 @@ public void yypushback(int number) { private void zzDoEOF() { if (!zzEOFDone) { zzEOFDone = true; - return; - + + return; } } @@ -411,7 +469,8 @@ private void zzDoEOF() { * @return the next token * @exception java.io.IOException if any I/O-Error occurs */ - public IElementType advance() throws java.io.IOException { + public IElementType advance() throws java.io.IOException + { int zzInput; int zzAction; @@ -445,7 +504,7 @@ public IElementType advance() throws java.io.IOException { while (true) { if (zzCurrentPosL < zzEndReadL) { - zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL); zzCurrentPosL += Character.charCount(zzInput); } else if (zzAtEOF) { @@ -467,11 +526,11 @@ else if (zzAtEOF) { break zzForAction; } else { - zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL); zzCurrentPosL += Character.charCount(zzInput); } } - int zzNext = zzTransL[ zzRowMapL[zzState] + ZZ_CMAP(zzInput) ]; + int zzNext = zzTransL[ zzRowMapL[zzState] + zzCMap(zzInput) ]; if (zzNext == -1) break zzForAction; zzState = zzNext; @@ -490,8 +549,8 @@ else if (zzAtEOF) { if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { zzAtEOF = true; - zzDoEOF(); - switch (zzLexicalState) { + zzDoEOF(); + switch (zzLexicalState) { case indent: { if (indent_levels.peek() != 0) { indent_levels.pop(); @@ -501,39 +560,39 @@ else if (zzAtEOF) { yybegin(YYINITIAL); } } // fall though - case 13: break; + case 16: break; default: return null; } } else { switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { - case 1: + case 1: { yypushback(1); indent_levels.push(0); yybegin(feature); - } - // fall through + } + // fall through case 9: break; - case 2: + case 2: { return TokenType.BAD_CHARACTER; - } - // fall through + } + // fall through case 10: break; - case 3: - { current_line_indent = 0; return FeatureModelTypes.CRLF; - } - // fall through + case 3: + { current_line_indent = (current_line_indent + TAB_WIDTH) & ~(TAB_WIDTH-1); + } + // fall through case 11: break; - case 4: - { current_line_indent++; - } - // fall through + case 4: + { current_line_indent = 0; return FeatureModelTypes.CRLF; + } + // fall through case 12: break; - case 5: - { current_line_indent = (current_line_indent + TAB_WIDTH) & ~(TAB_WIDTH-1); - } - // fall through + case 5: + { current_line_indent++; + } + // fall through case 13: break; - case 6: + case 6: { if(current_line_indent > indent_levels.peek()) { indent_levels.push(current_line_indent); yypushback(1); @@ -567,16 +626,16 @@ else if (current_line_indent == 0){ yybegin(feature); return FeatureModelTypes.CRLF; } - } - // fall through + } + // fall through case 14: break; - case 7: + case 7: { yybegin(indent); return FeatureModelTypes.FEATURENAME; - } - // fall through + } + // fall through case 15: break; - case 8: + case 8: { indent_levels.pop(); if(current_line_indent != indent_levels.peek()) { yypushback(1); @@ -587,8 +646,8 @@ else if (current_line_indent == 0){ yybegin(feature); return FeatureModelTypes.DEDENT; } - } - // fall through + } + // fall through case 16: break; default: zzScanError(ZZ_NO_MATCH); diff --git a/src/main/gen/se/isselab/HAnS/featureModel/parser/FeatureModelParser.java b/src/main/gen/se/isselab/HAnS/featureModel/parser/FeatureModelParser.java index 82f94aeb..4fc53434 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/parser/FeatureModelParser.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/parser/FeatureModelParser.java @@ -36,18 +36,36 @@ static boolean parse_root_(IElementType t, PsiBuilder b, int l) { } /* ********************************************************** */ - // FEATURENAME (CRLF+ ((INDENT) feature* DEDENT)?)? + // (FEATURENAME (OPTIONAL)?) (CRLF+ ((INDENT) feature* DEDENT)?)? public static boolean feature(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "feature")) return false; if (!nextTokenIs(b, FEATURENAME)) return false; boolean r; Marker m = enter_section_(b); - r = consumeToken(b, FEATURENAME); + r = feature_0(b, l + 1); r = r && feature_1(b, l + 1); exit_section_(b, m, FEATURE, r); return r; } + // FEATURENAME (OPTIONAL)? + private static boolean feature_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, FEATURENAME); + r = r && feature_0_1(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // (OPTIONAL)? + private static boolean feature_0_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_0_1")) return false; + consumeToken(b, OPTIONAL); + return true; + } + // (CRLF+ ((INDENT) feature* DEDENT)?)? private static boolean feature_1(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "feature_1")) return false; @@ -147,4 +165,49 @@ private static boolean featureModelFile_0_1_0(PsiBuilder b, int l) { return r; } + /* ********************************************************** */ + // "or" CRLF+ INDENT feature+ DEDENT + public static boolean orGroup(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "orGroup")) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, OR_GROUP, ""); + r = consumeToken(b, "or"); + r = r && orGroup_1(b, l + 1); + r = r && consumeToken(b, INDENT); + r = r && orGroup_3(b, l + 1); + r = r && consumeToken(b, DEDENT); + exit_section_(b, l, m, r, false, null); + return r; + } + + // CRLF+ + private static boolean orGroup_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "orGroup_1")) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, CRLF); + while (r) { + int c = current_position_(b); + if (!consumeToken(b, CRLF)) break; + if (!empty_element_parsed_guard_(b, "orGroup_1", c)) break; + } + exit_section_(b, m, null, r); + return r; + } + + // feature+ + private static boolean orGroup_3(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "orGroup_3")) return false; + boolean r; + Marker m = enter_section_(b); + r = feature(b, l + 1); + while (r) { + int c = current_position_(b); + if (!feature(b, l + 1)) break; + if (!empty_element_parsed_guard_(b, "orGroup_3", c)) break; + } + exit_section_(b, m, null, r); + return r; + } + } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelOrGroup.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelOrGroup.java new file mode 100644 index 00000000..3fe8bd79 --- /dev/null +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelOrGroup.java @@ -0,0 +1,13 @@ +// This is a generated file. Not intended for manual editing. +package se.isselab.HAnS.featureModel.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; + +public interface FeatureModelOrGroup extends PsiElement { + + @NotNull + List getFeatureList(); + +} diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelTypes.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelTypes.java index cd318ec0..9cc266ee 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelTypes.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelTypes.java @@ -9,11 +9,13 @@ public interface FeatureModelTypes { IElementType FEATURE = new FeatureModelElementType("FEATURE"); + IElementType OR_GROUP = new FeatureModelElementType("OR_GROUP"); IElementType CRLF = new FeatureModelTokenType("CRLF"); IElementType DEDENT = new FeatureModelTokenType("DEDENT"); IElementType FEATURENAME = new FeatureModelTokenType("FEATURENAME"); IElementType INDENT = new FeatureModelTokenType("INDENT"); + IElementType OPTIONAL = new FeatureModelTokenType("OPTIONAL"); class Factory { public static PsiElement createElement(ASTNode node) { @@ -21,6 +23,9 @@ public static PsiElement createElement(ASTNode node) { if (type == FEATURE) { return new FeatureModelFeatureImpl(node); } + else if (type == OR_GROUP) { + return new FeatureModelOrGroupImpl(node); + } throw new AssertionError("Unknown element type: " + type); } } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelVisitor.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelVisitor.java index e5b12d05..520b426b 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelVisitor.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelVisitor.java @@ -12,6 +12,10 @@ public void visitFeature(@NotNull FeatureModelFeature o) { visitFeatureAnnotationNamedElement(o); } + public void visitOrGroup(@NotNull FeatureModelOrGroup o) { + visitPsiElement(o); + } + public void visitFeatureAnnotationNamedElement(@NotNull FeatureAnnotationNamedElement o) { visitElement(o); } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelOrGroupImpl.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelOrGroupImpl.java new file mode 100644 index 00000000..a52a6e33 --- /dev/null +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelOrGroupImpl.java @@ -0,0 +1,36 @@ +// This is a generated file. Not intended for manual editing. +package se.isselab.HAnS.featureModel.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static se.isselab.HAnS.featureModel.psi.FeatureModelTypes.*; +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import se.isselab.HAnS.featureModel.psi.*; + +public class FeatureModelOrGroupImpl extends ASTWrapperPsiElement implements FeatureModelOrGroup { + + public FeatureModelOrGroupImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull FeatureModelVisitor visitor) { + visitor.visitOrGroup(this); + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof FeatureModelVisitor) accept((FeatureModelVisitor)visitor); + else super.accept(visitor); + } + + @Override + @NotNull + public List getFeatureList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, FeatureModelFeature.class); + } + +} diff --git a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.bnf b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.bnf index f8c3f258..12b5853a 100644 --- a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.bnf +++ b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.bnf @@ -33,7 +33,7 @@ limitations under the License. featureModelFile ::= (feature (feature)?)? // &begin[Referencing] -feature ::= (FEATURENAME (CRLF+ ((INDENT) feature* DEDENT)?)?) { +feature ::= ((FEATURENAME (OPTIONAL)?) (CRLF+ ((INDENT) feature* DEDENT)?)?) { mixin="se.isselab.HAnS.referencing.impl.FeatureAnnotationNamedElementImpl" implements="se.isselab.HAnS.referencing.FeatureAnnotationNamedElement" methods=[getLPQText getLPQStack renameFeature addFeature deleteFeature getName setName getNameIdentifier getFeatureName getPresentation @@ -41,4 +41,5 @@ addToFeatureModel deleteFromFeatureModel moveFeatureWithChildren deleteFeatureWi getTanglingDegree setTanglingDegree getScatteringDegree setScatteringDegree getLineCount setLineCount getMaxNestingDepth setMaxNestingDepth getMinNestingDepth setMinNestingDepth getAvgNestingDepth setAvgNestingDepth getNumberOfAnnotatedFiles setNumberOfAnnotatedFiles getNumberOfFileAnnotations setNumberOfFileAnnotations getNumberOfFolderAnnotations setNumberOfFolderAnnotations]} +orGroup ::= ("or" CRLF+ INDENT feature+ DEDENT) // &end[Referencing] \ No newline at end of file diff --git a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex index 945006a0..cf6cea34 100644 --- a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex +++ b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex @@ -39,7 +39,7 @@ SPACE= [' '] INDENT=[\t] FEATURENAME= [[A-Z]+|[a-z]+|[0-9]+|'_'+|'\''+] - +OPTIONAL=[?] %{ int current_line_indent = 0; int indent_level = 0; @@ -122,7 +122,7 @@ FEATURENAME= [[A-Z]+|[a-z]+|[0-9]+|'_'+|'\''+] } } -{FEATURENAME}+ { +{FEATURENAME}+ ({SPACE} {OPTIONAL})? { yybegin(indent); return FeatureModelTypes.FEATURENAME; } From 3e9d74105b962a49f2a75484c4967c569b10d0f3 Mon Sep 17 00:00:00 2001 From: Manhal Jasem Date: Thu, 27 Feb 2025 00:58:20 +0100 Subject: [PATCH 05/14] Optionally, OR/XOR and cross-tree constrains added to the Feature Model language --- .../HAnS/featureModel/FeatureModelLexer.java | 91 +++++--- .../parser/FeatureModelParser.java | 198 +++++++++++------- ....java => FeatureModelCrossConstrains.java} | 4 +- .../featureModel/psi/FeatureModelFeature.java | 3 + .../featureModel/psi/FeatureModelTypes.java | 16 +- .../featureModel/psi/FeatureModelVisitor.java | 8 +- ...a => FeatureModelCrossConstrainsImpl.java} | 10 +- .../psi/impl/FeatureModelFeatureImpl.java | 6 + .../HAnS/featureModel/FeatureModel.bnf | 6 +- .../HAnS/featureModel/FeatureModel.flex | 27 ++- 10 files changed, 234 insertions(+), 135 deletions(-) rename src/main/gen/se/isselab/HAnS/featureModel/psi/{FeatureModelOrGroup.java => FeatureModelCrossConstrains.java} (62%) rename src/main/gen/se/isselab/HAnS/featureModel/psi/impl/{FeatureModelOrGroupImpl.java => FeatureModelCrossConstrainsImpl.java} (73%) diff --git a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java index f116f4b8..66941517 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java @@ -39,6 +39,7 @@ public class FeatureModelLexer implements FlexLexer { public static final int indent = 2; public static final int feature = 4; public static final int dedent = 6; + public static final int cross = 8; /** * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l @@ -47,7 +48,7 @@ public class FeatureModelLexer implements FlexLexer { * l is of the form l = 2*k, k a non negative integer */ private static final int ZZ_LEXSTATE[] = { - 0, 0, 1, 1, 2, 2, 3, 3 + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4 }; /** @@ -85,9 +86,10 @@ private static int zzUnpackcmap_top(String packed, int offset, int [] result) { private static final String ZZ_CMAP_BLOCKS_PACKED_0 = "\11\0\1\1\1\2\2\3\1\2\22\0\1\4\6\0"+ - "\1\5\3\0\1\6\4\0\12\6\5\0\1\7\1\0"+ - "\32\6\4\0\1\6\1\0\32\6\1\0\1\10\10\0"+ - "\1\3\u01a2\0\2\3\326\0\u0100\3"; + "\1\5\3\0\1\6\4\0\12\6\3\0\1\7\1\10"+ + "\1\11\1\0\32\6\1\12\1\0\1\13\1\0\1\6"+ + "\1\0\16\6\1\14\2\6\1\15\5\6\1\16\2\6"+ + "\1\0\1\17\10\0\1\3\u01a2\0\2\3\326\0\u0100\3"; private static int [] zzUnpackcmap_blocks() { int [] result = new int[1024]; @@ -114,11 +116,12 @@ private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\4\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7"+ - "\1\10\1\0\2\7"; + "\5\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7"+ + "\1\10\2\6\1\11\1\12\1\13\1\2\1\14\2\0"+ + "\1\15\1\0"; private static int [] zzUnpackAction() { - int [] result = new int[15]; + int [] result = new int[24]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -143,11 +146,12 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\11\0\22\0\33\0\44\0\44\0\44\0\55"+ - "\0\44\0\44\0\66\0\44\0\77\0\110\0\44"; + "\0\0\0\20\0\40\0\60\0\100\0\120\0\120\0\120"+ + "\0\140\0\120\0\120\0\120\0\120\0\160\0\200\0\220"+ + "\0\120\0\240\0\260\0\120\0\300\0\160\0\120\0\320"; private static int [] zzUnpackRowMap() { - int [] result = new int[15]; + int [] result = new int[24]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -170,14 +174,16 @@ private static int zzUnpackRowMap(String packed, int offset, int [] result) { private static final int [] ZZ_TRANS = zzUnpacktrans(); private static final String ZZ_TRANS_PACKED_0 = - "\2\5\2\6\5\5\1\0\1\7\1\10\1\0\2\11"+ - "\1\12\1\0\1\10\5\6\2\13\1\6\1\13\2\14"+ - "\2\6\5\14\13\0\1\10\5\0\1\10\4\0\1\15"+ - "\1\16\1\13\1\0\1\13\7\0\1\17\5\0\1\15"+ - "\1\16\1\13\1\17\1\13"; + "\2\6\2\7\14\6\1\0\1\10\1\11\1\0\2\12"+ + "\1\13\2\0\1\14\1\15\1\0\1\16\1\13\1\17"+ + "\1\11\5\7\2\20\3\7\1\15\1\7\4\20\2\21"+ + "\2\7\14\21\5\7\2\22\1\23\3\7\1\24\4\22"+ + "\22\0\1\11\14\0\1\11\15\0\1\25\16\0\1\26"+ + "\10\0\2\20\5\0\4\20\5\0\2\22\5\0\4\22"+ + "\10\0\1\27\13\0\1\30\20\0\2\13\5\0\4\13"; private static int [] zzUnpacktrans() { - int [] result = new int[81]; + int [] result = new int[224]; int offset = 0; offset = zzUnpacktrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -215,11 +221,11 @@ private static int zzUnpacktrans(String packed, int offset, int [] result) { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\4\0\3\11\1\1\2\11\1\1\1\11\1\0\1\1"+ - "\1\11"; + "\5\0\3\11\1\1\4\11\3\1\1\11\2\1\1\11"+ + "\2\0\1\11\1\0"; private static int [] zzUnpackAttribute() { - int [] result = new int[15]; + int [] result = new int[24]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -560,7 +566,7 @@ else if (zzAtEOF) { yybegin(YYINITIAL); } } // fall though - case 16: break; + case 25: break; default: return null; } @@ -571,27 +577,27 @@ else if (zzAtEOF) { { yypushback(1); indent_levels.push(0); yybegin(feature); } // fall through - case 9: break; + case 14: break; case 2: { return TokenType.BAD_CHARACTER; } // fall through - case 10: break; + case 15: break; case 3: { current_line_indent = (current_line_indent + TAB_WIDTH) & ~(TAB_WIDTH-1); } // fall through - case 11: break; + case 16: break; case 4: { current_line_indent = 0; return FeatureModelTypes.CRLF; } // fall through - case 12: break; + case 17: break; case 5: { current_line_indent++; } // fall through - case 13: break; + case 18: break; case 6: { if(current_line_indent > indent_levels.peek()) { indent_levels.push(current_line_indent); @@ -628,14 +634,24 @@ else if (current_line_indent == 0){ } } // fall through - case 14: break; + case 19: break; case 7: - { yybegin(indent); - return FeatureModelTypes.FEATURENAME; + { return FeatureModelTypes.OPTIONAL; } // fall through - case 15: break; + case 20: break; case 8: + { yybegin(cross); return FeatureModelTypes.BRACKATSOPEN; + } + // fall through + case 21: break; + case 9: + { yybegin(indent); + return FeatureModelTypes.FEATURENAME; + } + // fall through + case 22: break; + case 10: { indent_levels.pop(); if(current_line_indent != indent_levels.peek()) { yypushback(1); @@ -648,7 +664,22 @@ else if (current_line_indent == 0){ } } // fall through - case 16: break; + case 23: break; + case 11: + { return FeatureModelTypes.FEATURE1; + } + // fall through + case 24: break; + case 12: + { yybegin(indent); return FeatureModelTypes.BRACKATSCLOSE; + } + // fall through + case 25: break; + case 13: + { return FeatureModelTypes.ARROW; + } + // fall through + case 26: break; default: zzScanError(ZZ_NO_MATCH); } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/parser/FeatureModelParser.java b/src/main/gen/se/isselab/HAnS/featureModel/parser/FeatureModelParser.java index 4fc53434..2fd0327f 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/parser/FeatureModelParser.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/parser/FeatureModelParser.java @@ -36,99 +36,190 @@ static boolean parse_root_(IElementType t, PsiBuilder b, int l) { } /* ********************************************************** */ - // (FEATURENAME (OPTIONAL)?) (CRLF+ ((INDENT) feature* DEDENT)?)? + // BRACKATSOPEN FEATURE1 ARROW FEATURE1 BRACKATSCLOSE (CRLF+ (cross_constrains)?)* + public static boolean cross_constrains(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cross_constrains")) return false; + if (!nextTokenIs(b, BRACKATSOPEN)) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeTokens(b, 0, BRACKATSOPEN, FEATURE1, ARROW, FEATURE1, BRACKATSCLOSE); + r = r && cross_constrains_5(b, l + 1); + exit_section_(b, m, CROSS_CONSTRAINS, r); + return r; + } + + // (CRLF+ (cross_constrains)?)* + private static boolean cross_constrains_5(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cross_constrains_5")) return false; + while (true) { + int c = current_position_(b); + if (!cross_constrains_5_0(b, l + 1)) break; + if (!empty_element_parsed_guard_(b, "cross_constrains_5", c)) break; + } + return true; + } + + // CRLF+ (cross_constrains)? + private static boolean cross_constrains_5_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cross_constrains_5_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = cross_constrains_5_0_0(b, l + 1); + r = r && cross_constrains_5_0_1(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // CRLF+ + private static boolean cross_constrains_5_0_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cross_constrains_5_0_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, CRLF); + while (r) { + int c = current_position_(b); + if (!consumeToken(b, CRLF)) break; + if (!empty_element_parsed_guard_(b, "cross_constrains_5_0_0", c)) break; + } + exit_section_(b, m, null, r); + return r; + } + + // (cross_constrains)? + private static boolean cross_constrains_5_0_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cross_constrains_5_0_1")) return false; + cross_constrains_5_0_1_0(b, l + 1); + return true; + } + + // (cross_constrains) + private static boolean cross_constrains_5_0_1_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "cross_constrains_5_0_1_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = cross_constrains(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + /* ********************************************************** */ + // (OR | XOR)? (FEATURENAME) (OPTIONAL)? (CRLF+ ((INDENT) feature* DEDENT)?)? (cross_constrains)? public static boolean feature(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "feature")) return false; - if (!nextTokenIs(b, FEATURENAME)) return false; boolean r; - Marker m = enter_section_(b); + Marker m = enter_section_(b, l, _NONE_, FEATURE, ""); r = feature_0(b, l + 1); - r = r && feature_1(b, l + 1); - exit_section_(b, m, FEATURE, r); + r = r && consumeToken(b, FEATURENAME); + r = r && feature_2(b, l + 1); + r = r && feature_3(b, l + 1); + r = r && feature_4(b, l + 1); + exit_section_(b, l, m, r, false, null); return r; } - // FEATURENAME (OPTIONAL)? + // (OR | XOR)? private static boolean feature_0(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "feature_0")) return false; + feature_0_0(b, l + 1); + return true; + } + + // OR | XOR + private static boolean feature_0_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_0_0")) return false; boolean r; - Marker m = enter_section_(b); - r = consumeToken(b, FEATURENAME); - r = r && feature_0_1(b, l + 1); - exit_section_(b, m, null, r); + r = consumeToken(b, OR); + if (!r) r = consumeToken(b, XOR); return r; } // (OPTIONAL)? - private static boolean feature_0_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "feature_0_1")) return false; + private static boolean feature_2(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_2")) return false; consumeToken(b, OPTIONAL); return true; } // (CRLF+ ((INDENT) feature* DEDENT)?)? - private static boolean feature_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "feature_1")) return false; - feature_1_0(b, l + 1); + private static boolean feature_3(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_3")) return false; + feature_3_0(b, l + 1); return true; } // CRLF+ ((INDENT) feature* DEDENT)? - private static boolean feature_1_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "feature_1_0")) return false; + private static boolean feature_3_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_3_0")) return false; boolean r; Marker m = enter_section_(b); - r = feature_1_0_0(b, l + 1); - r = r && feature_1_0_1(b, l + 1); + r = feature_3_0_0(b, l + 1); + r = r && feature_3_0_1(b, l + 1); exit_section_(b, m, null, r); return r; } // CRLF+ - private static boolean feature_1_0_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "feature_1_0_0")) return false; + private static boolean feature_3_0_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_3_0_0")) return false; boolean r; Marker m = enter_section_(b); r = consumeToken(b, CRLF); while (r) { int c = current_position_(b); if (!consumeToken(b, CRLF)) break; - if (!empty_element_parsed_guard_(b, "feature_1_0_0", c)) break; + if (!empty_element_parsed_guard_(b, "feature_3_0_0", c)) break; } exit_section_(b, m, null, r); return r; } // ((INDENT) feature* DEDENT)? - private static boolean feature_1_0_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "feature_1_0_1")) return false; - feature_1_0_1_0(b, l + 1); + private static boolean feature_3_0_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_3_0_1")) return false; + feature_3_0_1_0(b, l + 1); return true; } // (INDENT) feature* DEDENT - private static boolean feature_1_0_1_0(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "feature_1_0_1_0")) return false; + private static boolean feature_3_0_1_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_3_0_1_0")) return false; boolean r; Marker m = enter_section_(b); r = consumeToken(b, INDENT); - r = r && feature_1_0_1_0_1(b, l + 1); + r = r && feature_3_0_1_0_1(b, l + 1); r = r && consumeToken(b, DEDENT); exit_section_(b, m, null, r); return r; } // feature* - private static boolean feature_1_0_1_0_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "feature_1_0_1_0_1")) return false; + private static boolean feature_3_0_1_0_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_3_0_1_0_1")) return false; while (true) { int c = current_position_(b); if (!feature(b, l + 1)) break; - if (!empty_element_parsed_guard_(b, "feature_1_0_1_0_1", c)) break; + if (!empty_element_parsed_guard_(b, "feature_3_0_1_0_1", c)) break; } return true; } + // (cross_constrains)? + private static boolean feature_4(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_4")) return false; + feature_4_0(b, l + 1); + return true; + } + + // (cross_constrains) + private static boolean feature_4_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "feature_4_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = cross_constrains(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + /* ********************************************************** */ // (feature (feature)?)? static boolean featureModelFile(PsiBuilder b, int l) { @@ -165,49 +256,4 @@ private static boolean featureModelFile_0_1_0(PsiBuilder b, int l) { return r; } - /* ********************************************************** */ - // "or" CRLF+ INDENT feature+ DEDENT - public static boolean orGroup(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "orGroup")) return false; - boolean r; - Marker m = enter_section_(b, l, _NONE_, OR_GROUP, ""); - r = consumeToken(b, "or"); - r = r && orGroup_1(b, l + 1); - r = r && consumeToken(b, INDENT); - r = r && orGroup_3(b, l + 1); - r = r && consumeToken(b, DEDENT); - exit_section_(b, l, m, r, false, null); - return r; - } - - // CRLF+ - private static boolean orGroup_1(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "orGroup_1")) return false; - boolean r; - Marker m = enter_section_(b); - r = consumeToken(b, CRLF); - while (r) { - int c = current_position_(b); - if (!consumeToken(b, CRLF)) break; - if (!empty_element_parsed_guard_(b, "orGroup_1", c)) break; - } - exit_section_(b, m, null, r); - return r; - } - - // feature+ - private static boolean orGroup_3(PsiBuilder b, int l) { - if (!recursion_guard_(b, l, "orGroup_3")) return false; - boolean r; - Marker m = enter_section_(b); - r = feature(b, l + 1); - while (r) { - int c = current_position_(b); - if (!feature(b, l + 1)) break; - if (!empty_element_parsed_guard_(b, "orGroup_3", c)) break; - } - exit_section_(b, m, null, r); - return r; - } - } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelOrGroup.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelCrossConstrains.java similarity index 62% rename from src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelOrGroup.java rename to src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelCrossConstrains.java index 3fe8bd79..f4ef7869 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelOrGroup.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelCrossConstrains.java @@ -5,9 +5,9 @@ import org.jetbrains.annotations.*; import com.intellij.psi.PsiElement; -public interface FeatureModelOrGroup extends PsiElement { +public interface FeatureModelCrossConstrains extends PsiElement { @NotNull - List getFeatureList(); + List getCrossConstrainsList(); } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelFeature.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelFeature.java index 4855bdbb..081f0e01 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelFeature.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelFeature.java @@ -10,6 +10,9 @@ public interface FeatureModelFeature extends FeatureAnnotationNamedElement { + @Nullable + FeatureModelCrossConstrains getCrossConstrains(); + @NotNull List getFeatureList(); diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelTypes.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelTypes.java index 9cc266ee..ddcf1a1f 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelTypes.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelTypes.java @@ -8,23 +8,29 @@ public interface FeatureModelTypes { + IElementType CROSS_CONSTRAINS = new FeatureModelElementType("CROSS_CONSTRAINS"); IElementType FEATURE = new FeatureModelElementType("FEATURE"); - IElementType OR_GROUP = new FeatureModelElementType("OR_GROUP"); + IElementType ARROW = new FeatureModelTokenType("ARROW"); + IElementType BRACKATSCLOSE = new FeatureModelTokenType("BRACKATSCLOSE"); + IElementType BRACKATSOPEN = new FeatureModelTokenType("BRACKATSOPEN"); IElementType CRLF = new FeatureModelTokenType("CRLF"); IElementType DEDENT = new FeatureModelTokenType("DEDENT"); + IElementType FEATURE1 = new FeatureModelTokenType("FEATURE1"); IElementType FEATURENAME = new FeatureModelTokenType("FEATURENAME"); IElementType INDENT = new FeatureModelTokenType("INDENT"); IElementType OPTIONAL = new FeatureModelTokenType("OPTIONAL"); + IElementType OR = new FeatureModelTokenType("OR"); + IElementType XOR = new FeatureModelTokenType("XOR"); class Factory { public static PsiElement createElement(ASTNode node) { IElementType type = node.getElementType(); - if (type == FEATURE) { - return new FeatureModelFeatureImpl(node); + if (type == CROSS_CONSTRAINS) { + return new FeatureModelCrossConstrainsImpl(node); } - else if (type == OR_GROUP) { - return new FeatureModelOrGroupImpl(node); + else if (type == FEATURE) { + return new FeatureModelFeatureImpl(node); } throw new AssertionError("Unknown element type: " + type); } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelVisitor.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelVisitor.java index 520b426b..85aeb1e6 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelVisitor.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/FeatureModelVisitor.java @@ -8,12 +8,12 @@ public class FeatureModelVisitor extends PsiElementVisitor { - public void visitFeature(@NotNull FeatureModelFeature o) { - visitFeatureAnnotationNamedElement(o); + public void visitCrossConstrains(@NotNull FeatureModelCrossConstrains o) { + visitPsiElement(o); } - public void visitOrGroup(@NotNull FeatureModelOrGroup o) { - visitPsiElement(o); + public void visitFeature(@NotNull FeatureModelFeature o) { + visitFeatureAnnotationNamedElement(o); } public void visitFeatureAnnotationNamedElement(@NotNull FeatureAnnotationNamedElement o) { diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelOrGroupImpl.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelCrossConstrainsImpl.java similarity index 73% rename from src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelOrGroupImpl.java rename to src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelCrossConstrainsImpl.java index a52a6e33..7bd87a84 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelOrGroupImpl.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelCrossConstrainsImpl.java @@ -11,14 +11,14 @@ import com.intellij.extapi.psi.ASTWrapperPsiElement; import se.isselab.HAnS.featureModel.psi.*; -public class FeatureModelOrGroupImpl extends ASTWrapperPsiElement implements FeatureModelOrGroup { +public class FeatureModelCrossConstrainsImpl extends ASTWrapperPsiElement implements FeatureModelCrossConstrains { - public FeatureModelOrGroupImpl(@NotNull ASTNode node) { + public FeatureModelCrossConstrainsImpl(@NotNull ASTNode node) { super(node); } public void accept(@NotNull FeatureModelVisitor visitor) { - visitor.visitOrGroup(this); + visitor.visitCrossConstrains(this); } @Override @@ -29,8 +29,8 @@ public void accept(@NotNull PsiElementVisitor visitor) { @Override @NotNull - public List getFeatureList() { - return PsiTreeUtil.getChildrenOfTypeAsList(this, FeatureModelFeature.class); + public List getCrossConstrainsList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, FeatureModelCrossConstrains.class); } } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelFeatureImpl.java b/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelFeatureImpl.java index 47efb102..098fd000 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelFeatureImpl.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/psi/impl/FeatureModelFeatureImpl.java @@ -29,6 +29,12 @@ public void accept(@NotNull PsiElementVisitor visitor) { else super.accept(visitor); } + @Override + @Nullable + public FeatureModelCrossConstrains getCrossConstrains() { + return findChildByClass(FeatureModelCrossConstrains.class); + } + @Override @NotNull public List getFeatureList() { diff --git a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.bnf b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.bnf index 12b5853a..a151f4f5 100644 --- a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.bnf +++ b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.bnf @@ -29,11 +29,9 @@ limitations under the License. psiImplUtilClass="se.isselab.HAnS.featureModel.psi.impl.FeatureModelPsiImplUtil" } - featureModelFile ::= (feature (feature)?)? - // &begin[Referencing] -feature ::= ((FEATURENAME (OPTIONAL)?) (CRLF+ ((INDENT) feature* DEDENT)?)?) { +feature ::= ((OR | XOR)? (FEATURENAME) (OPTIONAL)? (CRLF+ ((INDENT) feature* DEDENT)?)? (cross_constrains)?) { mixin="se.isselab.HAnS.referencing.impl.FeatureAnnotationNamedElementImpl" implements="se.isselab.HAnS.referencing.FeatureAnnotationNamedElement" methods=[getLPQText getLPQStack renameFeature addFeature deleteFeature getName setName getNameIdentifier getFeatureName getPresentation @@ -41,5 +39,5 @@ addToFeatureModel deleteFromFeatureModel moveFeatureWithChildren deleteFeatureWi getTanglingDegree setTanglingDegree getScatteringDegree setScatteringDegree getLineCount setLineCount getMaxNestingDepth setMaxNestingDepth getMinNestingDepth setMinNestingDepth getAvgNestingDepth setAvgNestingDepth getNumberOfAnnotatedFiles setNumberOfAnnotatedFiles getNumberOfFileAnnotations setNumberOfFileAnnotations getNumberOfFolderAnnotations setNumberOfFolderAnnotations]} -orGroup ::= ("or" CRLF+ INDENT feature+ DEDENT) +cross_constrains ::= ( BRACKATSOPEN FEATURE1 ARROW FEATURE1 BRACKATSCLOSE (CRLF+ (cross_constrains)?)* ) // &end[Referencing] \ No newline at end of file diff --git a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex index cf6cea34..0129f4cb 100644 --- a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex +++ b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex @@ -15,6 +15,7 @@ limitations under the License. */ package se.isselab.HAnS.featureModel; +import com.intellij.lexer.FlexLexer; import com.intellij.psi.tree.IElementType; import se.isselab.HAnS.featureModel.psi.FeatureModelTypes; import com.intellij.psi.TokenType; @@ -37,9 +38,13 @@ CRLF=[\n|\r\n] SPACE= [' '] INDENT=[\t] - +XOR = "xor " +OR = "or " FEATURENAME= [[A-Z]+|[a-z]+|[0-9]+|'_'+|'\''+] -OPTIONAL=[?] +OPTIONAL=[\?] +BRACKATSOPEN=[\[] +BRACKATSCLOSE=[\]] +ARROW = "=>" %{ int current_line_indent = 0; int indent_level = 0; @@ -55,6 +60,7 @@ OPTIONAL=[?] %x indent %s feature %s dedent +%s cross %% . { yypushback(1); indent_levels.push(0); yybegin(feature); } @@ -62,7 +68,9 @@ OPTIONAL=[?] {SPACE} { current_line_indent++; } {INDENT} { current_line_indent = (current_line_indent + TAB_WIDTH) & ~(TAB_WIDTH-1); } {CRLF}+ { current_line_indent = 0; return FeatureModelTypes.CRLF; } - +{OPTIONAL} { return FeatureModelTypes.OPTIONAL; } +{BRACKATSOPEN} { yybegin(cross); return FeatureModelTypes.BRACKATSOPEN; } +{BRACKATSOPEN} { yybegin(cross); return FeatureModelTypes.BRACKATSOPEN; } . { indent_levels.pop(); if(current_line_indent != indent_levels.peek()) { @@ -76,7 +84,7 @@ OPTIONAL=[?] } } -{FEATURENAME} { +({OR} | {XOR})? {FEATURENAME} { if(current_line_indent > indent_levels.peek()) { indent_levels.push(current_line_indent); yypushback(1); @@ -111,7 +119,6 @@ OPTIONAL=[?] return FeatureModelTypes.CRLF; } } - <> { if (indent_levels.peek() != 0) { indent_levels.pop(); @@ -121,9 +128,11 @@ OPTIONAL=[?] yybegin(YYINITIAL); } } - -{FEATURENAME}+ ({SPACE} {OPTIONAL})? { - yybegin(indent); - return FeatureModelTypes.FEATURENAME; +{FEATURENAME}+ { + yybegin(indent); + return FeatureModelTypes.FEATURENAME; } +{BRACKATSCLOSE} { yybegin(indent); return FeatureModelTypes.BRACKATSCLOSE; } +{ARROW} { return FeatureModelTypes.ARROW; } +{FEATURENAME}+ { return FeatureModelTypes.FEATURE1; } [^] { return TokenType.BAD_CHARACTER; } From 8adab5e91b2c9a030daa66c88959f65286ad5fbe Mon Sep 17 00:00:00 2001 From: Manhal Jasem Date: Thu, 27 Feb 2025 03:27:57 +0100 Subject: [PATCH 06/14] OR/XOR highlighting part 2 --- .../FeatureModelHighlightingLexer.java | 68 ++++++++++++++----- .../HAnS/featureModel/FeatureModelLexer.java | 56 +++++++++------ .../HAnS/featureModel/FeatureModel.flex | 4 +- .../featureModel/FeatureModelAnnotator.java | 17 +++-- .../FeatureModelHighlightingLexer.flex | 13 +++- .../FeatureModelSyntaxHighlighter.java | 7 ++ 6 files changed, 117 insertions(+), 48 deletions(-) diff --git a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelHighlightingLexer.java b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelHighlightingLexer.java index b8c8496c..35c02471 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelHighlightingLexer.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelHighlightingLexer.java @@ -80,9 +80,10 @@ private static int zzUnpackcmap_top(String packed, int offset, int [] result) { private static final int [] ZZ_CMAP_BLOCKS = zzUnpackcmap_blocks(); private static final String ZZ_CMAP_BLOCKS_PACKED_0 = - "\11\0\1\1\1\2\2\0\1\2\22\0\1\1\6\0"+ - "\1\3\3\0\1\4\4\0\12\4\7\0\32\4\4\0"+ - "\1\4\1\0\32\4\1\0\1\5\u0183\0"; + "\11\0\1\1\1\2\2\0\1\2\22\0\1\3\6\0"+ + "\1\4\3\0\1\5\4\0\12\5\7\0\32\5\1\6"+ + "\1\0\1\7\1\0\1\5\1\0\16\5\1\10\2\5"+ + "\1\11\5\5\1\12\2\5\1\0\1\13\u0183\0"; private static int [] zzUnpackcmap_blocks() { int [] result = new int[512]; @@ -109,10 +110,11 @@ private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) private static final int [] ZZ_ACTION = zzUnpackAction(); private static final String ZZ_ACTION_PACKED_0 = - "\2\0\1\1\1\2\1\3\3\4"; + "\2\0\1\1\1\2\1\3\2\4\1\5\1\6\3\4"+ + "\2\1\2\4\2\0\1\7\1\4\1\0\1\10"; private static int [] zzUnpackAction() { - int [] result = new int[8]; + int [] result = new int[22]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -137,10 +139,12 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); private static final String ZZ_ROWMAP_PACKED_0 = - "\0\0\0\6\0\14\0\22\0\30\0\36\0\44\0\52"; + "\0\0\0\14\0\30\0\44\0\60\0\74\0\110\0\30"+ + "\0\30\0\124\0\140\0\154\0\170\0\204\0\220\0\234"+ + "\0\250\0\264\0\30\0\300\0\314\0\30"; private static int [] zzUnpackRowMap() { - int [] result = new int[8]; + int [] result = new int[22]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -163,13 +167,20 @@ private static int zzUnpackRowMap(String packed, int offset, int [] result) { private static final int [] ZZ_TRANS = zzUnpacktrans(); private static final String ZZ_TRANS_PACKED_0 = - "\1\3\1\4\1\5\1\6\1\7\1\10\1\3\1\4"+ - "\1\5\1\4\1\3\1\5\7\0\1\4\1\0\1\4"+ - "\4\0\1\5\2\0\1\5\1\0\1\4\1\0\1\6"+ - "\2\7\3\0\3\7\2\0\1\5\2\7\1\10"; + "\1\3\1\4\1\5\1\4\1\6\1\7\1\10\1\11"+ + "\1\12\1\7\1\13\1\14\1\3\1\4\1\5\2\4"+ + "\1\3\1\10\1\11\1\15\1\3\1\16\1\5\15\0"+ + "\1\4\1\0\2\4\11\0\1\5\10\0\1\5\1\0"+ + "\1\4\1\0\1\4\1\6\1\7\2\0\4\7\4\0"+ + "\2\7\2\0\4\7\4\0\2\7\2\0\1\7\1\17"+ + "\2\7\4\0\2\7\2\0\1\20\3\7\2\0\1\5"+ + "\1\0\2\7\2\0\3\7\1\14\11\0\1\21\12\0"+ + "\1\22\6\0\1\23\2\7\2\0\4\7\4\0\2\7"+ + "\2\0\1\7\1\24\2\7\3\0\1\23\21\0\1\25"+ + "\5\0\1\26\2\7\2\0\4\7\3\0\1\26\10\0"; private static int [] zzUnpacktrans() { - int [] result = new int[48]; + int [] result = new int[216]; int offset = 0; offset = zzUnpacktrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -207,10 +218,11 @@ private static int zzUnpacktrans(String packed, int offset, int [] result) { private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); private static final String ZZ_ATTRIBUTE_PACKED_0 = - "\2\0\1\11\5\1"; + "\2\0\1\11\4\1\2\11\7\1\2\0\1\11\1\1"+ + "\1\0\1\11"; private static int [] zzUnpackAttribute() { - int [] result = new int[8]; + int [] result = new int[22]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -537,22 +549,42 @@ else if (zzAtEOF) { { return TokenType.BAD_CHARACTER; } // fall through - case 5: break; + case 9: break; case 2: { yybegin(YYINITIAL); return FeatureModelTypes.INDENT; } // fall through - case 6: break; + case 10: break; case 3: { yybegin(YYINITIAL); return FeatureModelTypes.CRLF; } // fall through - case 7: break; + case 11: break; case 4: { yybegin(YYINITIAL); return FeatureModelTypes.FEATURENAME; } // fall through - case 8: break; + case 12: break; + case 5: + { yybegin(YYINITIAL); return FeatureModelTypes.BRACKATSOPEN; + } + // fall through + case 13: break; + case 6: + { yybegin(YYINITIAL); return FeatureModelTypes.BRACKATSCLOSE; + } + // fall through + case 14: break; + case 7: + { yybegin(YYINITIAL); return FeatureModelTypes.OR; + } + // fall through + case 15: break; + case 8: + { yybegin(YYINITIAL); return FeatureModelTypes.XOR; + } + // fall through + case 16: break; default: zzScanError(ZZ_NO_MATCH); } diff --git a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java index 66941517..0caa08ec 100644 --- a/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java +++ b/src/main/gen/se/isselab/HAnS/featureModel/FeatureModelLexer.java @@ -118,10 +118,10 @@ private static int zzUnpackcmap_blocks(String packed, int offset, int [] result) private static final String ZZ_ACTION_PACKED_0 = "\5\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7"+ "\1\10\2\6\1\11\1\12\1\13\1\2\1\14\2\0"+ - "\1\15\1\0"; + "\1\15\1\16\1\0\1\17"; private static int [] zzUnpackAction() { - int [] result = new int[24]; + int [] result = new int[26]; int offset = 0; offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); return result; @@ -148,10 +148,11 @@ private static int zzUnpackAction(String packed, int offset, int [] result) { private static final String ZZ_ROWMAP_PACKED_0 = "\0\0\0\20\0\40\0\60\0\100\0\120\0\120\0\120"+ "\0\140\0\120\0\120\0\120\0\120\0\160\0\200\0\220"+ - "\0\120\0\240\0\260\0\120\0\300\0\160\0\120\0\320"; + "\0\120\0\240\0\260\0\120\0\300\0\320\0\120\0\120"+ + "\0\340\0\120"; private static int [] zzUnpackRowMap() { - int [] result = new int[24]; + int [] result = new int[26]; int offset = 0; offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); return result; @@ -180,10 +181,11 @@ private static int zzUnpackRowMap(String packed, int offset, int [] result) { "\2\7\14\21\5\7\2\22\1\23\3\7\1\24\4\22"+ "\22\0\1\11\14\0\1\11\15\0\1\25\16\0\1\26"+ "\10\0\2\20\5\0\4\20\5\0\2\22\5\0\4\22"+ - "\10\0\1\27\13\0\1\30\20\0\2\13\5\0\4\13"; + "\10\0\1\27\13\0\1\30\30\0\1\31\6\0\1\32"+ + "\13\0"; private static int [] zzUnpacktrans() { - int [] result = new int[224]; + int [] result = new int[240]; int offset = 0; offset = zzUnpacktrans(ZZ_TRANS_PACKED_0, offset, result); return result; @@ -222,10 +224,10 @@ private static int zzUnpacktrans(String packed, int offset, int [] result) { private static final String ZZ_ATTRIBUTE_PACKED_0 = "\5\0\3\11\1\1\4\11\3\1\1\11\2\1\1\11"+ - "\2\0\1\11\1\0"; + "\2\0\2\11\1\0\1\11"; private static int [] zzUnpackAttribute() { - int [] result = new int[24]; + int [] result = new int[26]; int offset = 0; offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); return result; @@ -566,7 +568,7 @@ else if (zzAtEOF) { yybegin(YYINITIAL); } } // fall though - case 25: break; + case 27: break; default: return null; } @@ -577,27 +579,27 @@ else if (zzAtEOF) { { yypushback(1); indent_levels.push(0); yybegin(feature); } // fall through - case 14: break; + case 16: break; case 2: { return TokenType.BAD_CHARACTER; } // fall through - case 15: break; + case 17: break; case 3: { current_line_indent = (current_line_indent + TAB_WIDTH) & ~(TAB_WIDTH-1); } // fall through - case 16: break; + case 18: break; case 4: { current_line_indent = 0; return FeatureModelTypes.CRLF; } // fall through - case 17: break; + case 19: break; case 5: { current_line_indent++; } // fall through - case 18: break; + case 20: break; case 6: { if(current_line_indent > indent_levels.peek()) { indent_levels.push(current_line_indent); @@ -634,23 +636,23 @@ else if (current_line_indent == 0){ } } // fall through - case 19: break; + case 21: break; case 7: { return FeatureModelTypes.OPTIONAL; } // fall through - case 20: break; + case 22: break; case 8: { yybegin(cross); return FeatureModelTypes.BRACKATSOPEN; } // fall through - case 21: break; + case 23: break; case 9: { yybegin(indent); return FeatureModelTypes.FEATURENAME; } // fall through - case 22: break; + case 24: break; case 10: { indent_levels.pop(); if(current_line_indent != indent_levels.peek()) { @@ -664,22 +666,32 @@ else if (current_line_indent == 0){ } } // fall through - case 23: break; + case 25: break; case 11: { return FeatureModelTypes.FEATURE1; } // fall through - case 24: break; + case 26: break; case 12: { yybegin(indent); return FeatureModelTypes.BRACKATSCLOSE; } // fall through - case 25: break; + case 27: break; case 13: { return FeatureModelTypes.ARROW; } // fall through - case 26: break; + case 28: break; + case 14: + { yybegin(feature); return FeatureModelTypes.OR; + } + // fall through + case 29: break; + case 15: + { yybegin(feature); return FeatureModelTypes.XOR; + } + // fall through + case 30: break; default: zzScanError(ZZ_NO_MATCH); } diff --git a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex index 0129f4cb..cfb15eda 100644 --- a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex +++ b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex @@ -69,6 +69,8 @@ ARROW = "=>" {INDENT} { current_line_indent = (current_line_indent + TAB_WIDTH) & ~(TAB_WIDTH-1); } {CRLF}+ { current_line_indent = 0; return FeatureModelTypes.CRLF; } {OPTIONAL} { return FeatureModelTypes.OPTIONAL; } +{OR} { yybegin(feature); return FeatureModelTypes.OR;} +{XOR} { yybegin(feature); return FeatureModelTypes.XOR;} {BRACKATSOPEN} { yybegin(cross); return FeatureModelTypes.BRACKATSOPEN; } {BRACKATSOPEN} { yybegin(cross); return FeatureModelTypes.BRACKATSOPEN; } . { @@ -84,7 +86,7 @@ ARROW = "=>" } } -({OR} | {XOR})? {FEATURENAME} { +{FEATURENAME} { if(current_line_indent > indent_levels.peek()) { indent_levels.push(current_line_indent); yypushback(1); diff --git a/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelAnnotator.java b/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelAnnotator.java index 326cfe6a..1a9f54af 100644 --- a/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelAnnotator.java +++ b/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelAnnotator.java @@ -40,12 +40,17 @@ public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder hold Query psiReferences = ReferencesSearch.search(feature); if (psiReferences.findFirst() == null) { - holder.newAnnotation(HighlightSeverity.WEAK_WARNING, "Feature is never used") - .range(feature.getFirstChild().getTextRange()) - .highlightType(ProblemHighlightType.LIKE_UNUSED_SYMBOL) - // ** Tutorial step 18.3 - Add a quick fix for the string containing possible properties - //.withFix(new FeatureModelCreateNewFeature(featureText)) - .create(); + if (feature.getFirstChild().getText().endsWith("or ") || feature.getFirstChild().getText().endsWith("xor ")){ + holder.newSilentAnnotation(HighlightSeverity.INFORMATION) + .range(feature.getFirstChild().getTextRange()).textAttributes(FeatureModelSyntaxHighlighter.OPERATION).create(); + } else { + holder.newAnnotation(HighlightSeverity.WEAK_WARNING, "Feature is never used") + .range(feature.getFirstChild().getTextRange()) + .highlightType(ProblemHighlightType.LIKE_UNUSED_SYMBOL) + // ** Tutorial step 18.3 - Add a quick fix for the string containing possible properties + //.withFix(new FeatureModelCreateNewFeature(featureText)) + .create(); + } } else { // Found at least one property, force the text attributes to Simple syntax value character holder.newSilentAnnotation(HighlightSeverity.INFORMATION) diff --git a/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelHighlightingLexer.flex b/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelHighlightingLexer.flex index 0b45fc1c..a4a78133 100644 --- a/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelHighlightingLexer.flex +++ b/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelHighlightingLexer.flex @@ -34,9 +34,13 @@ CRLF=[\n|\r\n] SPACE= [' '] INDENT=[\t] - +XOR = "xor " +OR = "or " FEATURENAME= [[A-Z]+|[a-z]+|[0-9]+|'_'+|'\''+] +BRACKATSOPEN=[\[] +BRACKATSCLOSE=[\]] + %state WAITING_VALUE %% @@ -51,4 +55,11 @@ FEATURENAME= [[A-Z]+|[a-z]+|[0-9]+|'_'+|'\''+] ({SPACE}|{INDENT})+ { yybegin(YYINITIAL); return FeatureModelTypes.INDENT; } +{OR} { yybegin(YYINITIAL); return FeatureModelTypes.OR;} + +{XOR} { yybegin(YYINITIAL); return FeatureModelTypes.XOR;} + +{BRACKATSOPEN} { yybegin(YYINITIAL); return FeatureModelTypes.BRACKATSOPEN;} + +{BRACKATSCLOSE} { yybegin(YYINITIAL); return FeatureModelTypes.BRACKATSCLOSE;} [^] { return TokenType.BAD_CHARACTER; } diff --git a/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelSyntaxHighlighter.java b/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelSyntaxHighlighter.java index 4e194234..3ca3bd26 100644 --- a/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelSyntaxHighlighter.java +++ b/src/main/java/se/isselab/HAnS/syntaxHighlighting/featureModel/FeatureModelSyntaxHighlighter.java @@ -33,12 +33,15 @@ public class FeatureModelSyntaxHighlighter extends SyntaxHighlighterBase { public static final TextAttributesKey FEATURE = createTextAttributesKey("FEATURENAME", DefaultLanguageHighlighterColors.CONSTANT); + public static final TextAttributesKey OPERATION = + createTextAttributesKey("OPERATION", DefaultLanguageHighlighterColors.KEYWORD); public static final TextAttributesKey BAD_CHARACTER = createTextAttributesKey("HAnS_BAD_CHARACTER", HighlighterColors.BAD_CHARACTER); private static final TextAttributesKey[] BAD_CHAR_KEYS = new TextAttributesKey[]{BAD_CHARACTER}; private static final TextAttributesKey[] FEATURE_KEYS = new TextAttributesKey[]{FEATURE}; + private static final TextAttributesKey[] OPERATION_KEYS = new TextAttributesKey[]{OPERATION}; private static final TextAttributesKey[] EMPTY_KEYS = new TextAttributesKey[0]; @Override @@ -50,6 +53,10 @@ public class FeatureModelSyntaxHighlighter extends SyntaxHighlighterBase { public TextAttributesKey @NotNull [] getTokenHighlights(IElementType tokenType) { if (tokenType.equals(FeatureModelTypes.FEATURENAME)){ return FEATURE_KEYS; + } else if (tokenType.equals(FeatureModelTypes.OR)) { + return OPERATION_KEYS; + } else if (tokenType.equals(FeatureModelTypes.XOR)) { + return OPERATION_KEYS; } else if (tokenType.equals(TokenType.BAD_CHARACTER)) { return BAD_CHAR_KEYS; } else { From e2bd346f7c29be5f009f5d6dab5f7e21620dab9f Mon Sep 17 00:00:00 2001 From: Manhal Jasem Date: Thu, 27 Feb 2025 03:55:04 +0100 Subject: [PATCH 07/14] HAnS TrafficLight Feature annotated --- .feature-model | 6 ++++++ .../HAnS/trafficLight/.feature-to-folder | 1 + .../trafficLight/HansTrafficLightWidget.java | 21 +++++++++++-------- 3 files changed, 19 insertions(+), 9 deletions(-) create mode 100644 src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder diff --git a/.feature-model b/.feature-model index 1a37547f..7bba7413 100644 --- a/.feature-model +++ b/.feature-model @@ -36,6 +36,12 @@ HAnS ExtensionPoint Callback Service + TrafficLight + WidgetLocation + WidgetStyle + SearchFeatures + ClickAndHover + HoverPopupStyle FileHighlighter FeatureView FileTemplate diff --git a/src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder b/src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder new file mode 100644 index 00000000..246f2034 --- /dev/null +++ b/src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder @@ -0,0 +1 @@ +TrafficLight \ No newline at end of file diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java index 97ef1d1f..b5ac5584 100644 --- a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java +++ b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java @@ -41,7 +41,7 @@ import java.util.Map; import java.util.Objects; import java.util.Set; - +// &begin[WidgetLocation] public class HansTrafficLightWidget extends JPanel { private AnAction action; private Presentation presentation; @@ -60,7 +60,7 @@ public class HansTrafficLightWidget extends JPanel { this.place = place; this.editor = editor; setOpaque(false); - + // &begin[WidgetStyle] hansIcon = new JLabel(); if (!SystemInfo.isWindows) { @@ -75,13 +75,13 @@ public class HansTrafficLightWidget extends JPanel { )); hansIcon.setIcon(AnnotationIcons.PluginIcon); - + // &end[WidgetStyle] hansIcon.setVisible(false); searchFeatures(); add(hansIcon); - + // &begin[ClickAndHover] mouseListener = new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { @@ -144,9 +144,9 @@ public boolean isBorderOpaque() { var disposable = Disposer.newDisposable(); EditorUtil.disposeWithEditor(editor, disposable); } - + // &end[ClickAndHover] } - + // &begin[SearchFeatures] private void searchFeatures() { new GetFeatureFileMappings(this.editor.getProject(), "Find Feature File Mappings", new FeatureFileMappingCallback() { @Override @@ -169,6 +169,7 @@ public void onComplete(Map featureFileMappings) { } }).queue(); } + // &end[SearchFeatures] @Override public void removeNotify() { @@ -180,7 +181,7 @@ public void addNotify() { super.addNotify(); addMouseListener(mouseListener); } - + // &begin[HoverPopupStyle] private void showPopupWithMappingName() { Notification notification = new Notification( "notification", @@ -190,7 +191,7 @@ private void showPopupWithMappingName() { ); Notifications.Bus.notify(notification); } - + // &end[HoverPopupStyle] private void openMappingsFile() { VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(filePath)); if (virtualFile != null && this.editor.getProject() != null) { @@ -199,7 +200,7 @@ private void openMappingsFile() { JOptionPane.showMessageDialog(null, "File not found: " + filePath); } } - + // &begin[WidgetStyle] @Override protected void paintComponent(Graphics graphics) { if (filePath == null) return; @@ -217,4 +218,6 @@ protected void paintComponent(Graphics graphics) { ActionButtonLook.SYSTEM_LOOK.paintLookBackground(graphics, rect, color); } + // &end[WidgetStyle] } +// &end[WidgetLocation] From e57d7db291c4370653752d550eecb28a2b7b6b97 Mon Sep 17 00:00:00 2001 From: Manhal Jasem Date: Thu, 27 Feb 2025 21:21:36 +0100 Subject: [PATCH 08/14] extending Feature Modeling language --- src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex index cfb15eda..d76a9c6c 100644 --- a/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex +++ b/src/main/java/se/isselab/HAnS/featureModel/FeatureModel.flex @@ -138,3 +138,4 @@ ARROW = "=>" {ARROW} { return FeatureModelTypes.ARROW; } {FEATURENAME}+ { return FeatureModelTypes.FEATURE1; } [^] { return TokenType.BAD_CHARACTER; } + From 9163bfefa7b26cc6089b79e4e44919e5b5d2a076 Mon Sep 17 00:00:00 2001 From: ManhalJasem <96029523+ManhalJasem@users.noreply.github.com> Date: Sat, 8 Mar 2025 17:38:38 +0100 Subject: [PATCH 09/14] Delete .feature-model --- .feature-model | 51 -------------------------------------------------- 1 file changed, 51 deletions(-) delete mode 100644 .feature-model diff --git a/.feature-model b/.feature-model deleted file mode 100644 index 7bba7413..00000000 --- a/.feature-model +++ /dev/null @@ -1,51 +0,0 @@ -HAnS - FeatureModel - Language - File - FolderAnnotation - Language - File - FileAnnotation - Language - File - CodeAnnotation - Language - File - Injection - JavaStyleComment - CodeCompletion - FileNameProvider - LiveTemplate - SyntaxHighlighting - FeatureModel - FolderAnnotation - FileAnnotation - CodeAnnotation - ColorSettingsPage - Referencing - FeatureLocation - Metrics - LineCount - FeatureFileMapping - Scattering - Tangling - NestingDepths - NumberOfAnnotatedFiles - NumberOfFeatures - MetricsView - ExtensionPoint - Callback - Service - TrafficLight - WidgetLocation - WidgetStyle - SearchFeatures - ClickAndHover - HoverPopupStyle - FileHighlighter - FeatureView - FileTemplate - NewFile - Quickfix - SettingsPage - From 5ee6ff1e68058406b1dc572ffb4b2cc5a69f6f87 Mon Sep 17 00:00:00 2001 From: ManhalJasem <96029523+ManhalJasem@users.noreply.github.com> Date: Sat, 8 Mar 2025 17:39:07 +0100 Subject: [PATCH 10/14] Delete src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java --- .../featureLocation/FeatureFileMapping.java | 272 ------------------ 1 file changed, 272 deletions(-) delete mode 100644 src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java diff --git a/src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java b/src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java deleted file mode 100644 index f46dba08..00000000 --- a/src/main/java/se/isselab/HAnS/featureLocation/FeatureFileMapping.java +++ /dev/null @@ -1,272 +0,0 @@ -/* -Copyright 2024 David Stechow & Philipp Kusmierz - -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 se.isselab.HAnS.featureLocation; - - -import com.intellij.openapi.application.ReadAction; -import com.intellij.openapi.util.Pair; -import se.isselab.HAnS.featureModel.psi.FeatureModelFeature; - -import java.util.*; -import java.util.stream.Collectors; - - -/** - * Structure which holds information of all locations inside the project for a given Feature. - */ -public class FeatureFileMapping { - - public enum MarkerType {BEGIN, END, LINE, NONE} - - public enum AnnotationType {FOLDER, FILE, CODE} - - private final HashMap, Pair>> map = new HashMap<>(); - private HashMap, Pair>>> cache = new HashMap<>(); - private final FeatureModelFeature mappedFeature; - - public FeatureFileMapping(FeatureModelFeature feature) { - mappedFeature = feature; - } - - /** - * Caches data for later processing via buildFromQueue() - * This function should be called for each marker for a given feature before buildFromQueue() is called - * - * @param path the file path which is mapped to the given line number - * @param lineNumber the line number within the specified file - * @param type the type of the feature marker - * @param annotationType the annotation type - {file, folder, code} - * @see #buildFromQueue() - */ - public void enqueue(String path, int lineNumber, MarkerType type, AnnotationType annotationType, String originatingFilePath) { - var key = new Pair<>(path, originatingFilePath); - if (cache.get(key) != null) { - if (cache.get(key).first != annotationType) - // handle case when feature is annotated multiple times to same asset - System.err.println("Feature is linked to file via different annotation types. This can result in inaccurate metrics. " + "[Feature: " + ReadAction.compute(mappedFeature::getLPQText) + "][File: " + path + "]"); - cache.get(key).second.add(new Pair<>(type, lineNumber)); - } else { - - ArrayList> arr = new ArrayList<>(); - arr.add(new Pair<>(type, lineNumber)); - cache.put(key, new Pair<>(annotationType, arr)); - } - } - - /** - * Builds the cached data provided by enqueue() into corresponding featureLocationBlock-structures - * - * @see #enqueue(String, int, MarkerType, AnnotationType, String) - */ - public void buildFromQueue() { - if (cache == null || cache.isEmpty()) - return; - - for (var entry : cache.entrySet()) { //building featureLocationBlocks from cache entries - Deque stack = new ArrayDeque<>(); - var key = entry.getKey(); - var annotationTypeToLocationBlockPair = entry.getValue(); - - //sort in ascending order - cache.get(key).second.sort(Comparator.comparing(p -> p.second)); - - //create a featureLocationBlock for each (begin,end) or line - for (var markerToLinePair : annotationTypeToLocationBlockPair.second) { - - switch (markerToLinePair.first) { - case BEGIN -> stack.push(markerToLinePair.second); - case END -> { - if (stack.isEmpty()) { - // found end marker without begin marker - System.err.printf("Found &end marker without matching &begin marker in [%s] at line [%d]. This will result in inaccurate metrics", key.first, markerToLinePair.second + 1); - continue; - } - int beginLine = stack.pop(); - add(key, new FeatureLocationBlock(beginLine, markerToLinePair.second), annotationTypeToLocationBlockPair.first); - } - case LINE -> add(key, new FeatureLocationBlock(markerToLinePair.second, markerToLinePair.second), annotationTypeToLocationBlockPair.first); - case NONE -> // should only happen if file is a feature-to-file or feature-to-folder - add(key, new FeatureLocationBlock(0, markerToLinePair.second), annotationTypeToLocationBlockPair.first); - default -> { - // should not happen but cover case if no label was found - } - } - } - if (!stack.isEmpty()) { - // there was a begin without an endmarker - for (var line : stack) { - // handle case when there was a begin marker without an end marker - String errorMessage = String.format("Missing closing &end marker for &begin in [%s] at line [%d]. This will result in inaccurate metrics", key.first, line + 1); - System.err.printf(errorMessage); - } - } - } - - //clear cache and file - cache = new HashMap<>(); - } - - /** - * Method to get the Feature mapped to the FeatureFileMapping - * - * @return FeatureModelFeature mapped to the FeatureFileMapping - */ - public FeatureModelFeature getFeature() { - return mappedFeature; - } - - - /** - * Maps the given file to a FeatureLocationBlock. - * - * @param pathPairOriginatingPath the file pathPairOriginatingPath which is mapped to a given block - * @param block the location of the feature block inside the given file - * @param annotationType the annotation type for the corresponding filepath - */ - private void add(Pair pathPairOriginatingPath, FeatureLocationBlock block, AnnotationType annotationType) { - //check if file is already mapped to given feature - - //add block to already existing arraylist - map.computeIfPresent(pathPairOriginatingPath, (k,v) -> { - v.second.add(block); - return v; - }); - - //add file and location to map - ArrayList list = new ArrayList<>(); - list.add(block); - map.put(pathPairOriginatingPath, new Pair<>(annotationType, list)); - } - // &begin[FeatureLocation] - - /** - * Method to get all FeatureLocations of the corresponding feature - * - * @return List of all FeatureLocations of the corresponding feature - */ - public ArrayList getFeatureLocations() { - ArrayList result = new ArrayList<>(); - for (var entry : map.entrySet()) { - FeatureLocation location = new FeatureLocation(entry.getKey().first, entry.getKey().second, mappedFeature, entry.getValue().first, entry.getValue().second); - result.add(location); - } - return result; - } - // &end[FeatureLocation] - - // &begin[FeatureLocation] - - /** - * Method to get the FeatureLocations of a file for the corresponding feature - * - * @param filePathPair The File path paired with the origin of the annotation to retrieve the feature locations from - * @return FeatureLocation structure which holds information on feature locations inside given path - */ - public FeatureLocation getFeatureLocationsForFile(Pair filePathPair) { - if (!map.containsKey(filePathPair)) - return null; - - var entry = map.get(filePathPair); - return new FeatureLocation(filePathPair.first, filePathPair.second, mappedFeature, entry.first, entry.second); - } - // &end[FeatureLocation] - - /** - * Method to get a Set of all File paths tangled with the current feature - * - * @return Set of all related Paths - */ - public Set getMappedFilePaths() { - var keys = map.keySet(); - Set result = new HashSet<>(); - for (var key : keys) { - result.add(key.first); - } - return result; - } - - public Set> getMappedPathPair() { - return map.keySet(); - } - - public Set getFileMappings() { - - var keys = map.keySet(); - Set result = new HashSet<>(); - - for (var key: keys) { - var val = map.get(key); - if (val.first.name().equals("FILE") || val.first.name().equals("FOLDER")) { - result.add(key.first + ":" + key.second); - } - } - return result; - } - // &begin[LineCount] - - /** - * Method to get the total line-count of a feature in a file specified by path - * - * @param pathPairOrigin path of the file which should be checked - * @return line-count of a feature in the given file - */ - public int getFeatureLineCountInFile(Pair pathPairOrigin) { - var annotationTypeToBlocksPair = map.get(pathPairOrigin); - if (annotationTypeToBlocksPair == null) - return 0; - - HashSet lineSet = new HashSet<>(); - //add each individual line to the set - for (FeatureLocationBlock block : annotationTypeToBlocksPair.second) { - for (int i = block.getStartLine(); i <= block.getEndLine(); i++) { - lineSet.add(i); - } - } - return lineSet.size(); - } - // &end[LineCount] - - // &begin[LineCount] - - /** - * Method to get the total line-count of a feature for all files - * - * @return line-count of a feature - */ - public int getTotalFeatureLineCount() { - int total = 0; - - for (var key : map.keySet()) { - total += getFeatureLineCountInFile(key); - } - - return total; - } - // &end[LineCount] - - public Map> getFolderAnnotations() { - var featureLocations = getFeatureLocations(); - return featureLocations.stream().filter(fl -> fl.getAnnotationType() == AnnotationType.FOLDER) - .collect(Collectors.groupingBy(FeatureLocation::getMappedBy)); - } - - public Map> getFileAnnotations() { - var featureLocations = getFeatureLocations(); - return featureLocations.stream().filter(fl -> fl.getAnnotationType() == AnnotationType.FILE) - .collect(Collectors.groupingBy(FeatureLocation::getMappedBy)); - } -} From 6dca281c27a72dc087b469acbdaec0317412b014 Mon Sep 17 00:00:00 2001 From: ManhalJasem <96029523+ManhalJasem@users.noreply.github.com> Date: Sat, 8 Mar 2025 17:39:44 +0100 Subject: [PATCH 11/14] Delete src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder --- src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder diff --git a/src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder b/src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder deleted file mode 100644 index 246f2034..00000000 --- a/src/main/java/se/isselab/HAnS/trafficLight/.feature-to-folder +++ /dev/null @@ -1 +0,0 @@ -TrafficLight \ No newline at end of file From 6909c059d35a2976c7b4b1b3e0f3c84792dbf22a Mon Sep 17 00:00:00 2001 From: ManhalJasem <96029523+ManhalJasem@users.noreply.github.com> Date: Sat, 8 Mar 2025 17:39:56 +0100 Subject: [PATCH 12/14] Delete src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java --- .../trafficLight/HansTrafficLightAction.java | 59 ------------------- 1 file changed, 59 deletions(-) delete mode 100644 src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java deleted file mode 100644 index 5e4688a5..00000000 --- a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightAction.java +++ /dev/null @@ -1,59 +0,0 @@ -package se.isselab.HAnS.trafficLight; - -import com.intellij.openapi.actionSystem.ActionUpdateThread; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.Presentation; -import com.intellij.openapi.actionSystem.ex.CustomComponentAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.project.DumbAware; -import org.jetbrains.annotations.NotNull; - -import javax.swing.*; - -public class HansTrafficLightAction extends AnAction implements DumbAware, CustomComponentAction { - private Editor editor; - HansTrafficLightAction() { - super(); - } - HansTrafficLightAction(Editor editor) { - this.editor = editor; - } - - @Override - public @NotNull JComponent createCustomComponent(@NotNull Presentation presentation, @NotNull String place) { - return new HansTrafficLightWidget(this, presentation, place, editor); - } - - @Override - public void updateCustomComponent(@NotNull JComponent component, @NotNull Presentation presentation) { - CustomComponentAction.super.updateCustomComponent(component, presentation); - } - - @Override - public void actionPerformed(@NotNull AnActionEvent anActionEvent) { - - } - - @Override - public @NotNull ActionUpdateThread getActionUpdateThread() { - return ActionUpdateThread.BGT; - } - - @Override - public final void update(AnActionEvent e) { - var p = e.getProject(); - if (p == null || !p.isInitialized() || p.isDisposed()) { - e.getPresentation().setEnabledAndVisible(false); - return; - } - var visible = e.getPresentation().isVisible(); - e.getPresentation().setVisible(visible); - if (!visible) { - e.getPresentation().setEnabled(false); - return; - } - - e.getPresentation().setEnabled(true); - } -} From f8e6c6dc7e7501cc3b41fc81f1a743b59cd54dde Mon Sep 17 00:00:00 2001 From: ManhalJasem <96029523+ManhalJasem@users.noreply.github.com> Date: Sat, 8 Mar 2025 17:40:15 +0100 Subject: [PATCH 13/14] Delete src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java --- .../HansTrafficLightActionProvider.java | 23 ------------------- 1 file changed, 23 deletions(-) delete mode 100644 src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java deleted file mode 100644 index e03f88ed..00000000 --- a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightActionProvider.java +++ /dev/null @@ -1,23 +0,0 @@ -package se.isselab.HAnS.trafficLight; - -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.DefaultActionGroup; -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.EditorKind; -import com.intellij.openapi.actionSystem.Separator; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.markup.InspectionWidgetActionProvider; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class HansTrafficLightActionProvider implements InspectionWidgetActionProvider { - - @Override - public @Nullable AnAction createAction(@NotNull Editor editor) { - if (editor.getEditorKind() == EditorKind.MAIN_EDITOR) { - return new DefaultActionGroup(new HansTrafficLightAction(editor), Separator.create()); - } - return null; - } -} From 4b8aff864f406cb30dbf80e3d27df817214d56df Mon Sep 17 00:00:00 2001 From: ManhalJasem <96029523+ManhalJasem@users.noreply.github.com> Date: Sat, 8 Mar 2025 17:40:48 +0100 Subject: [PATCH 14/14] Delete src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java --- .../trafficLight/HansTrafficLightWidget.java | 223 ------------------ 1 file changed, 223 deletions(-) delete mode 100644 src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java diff --git a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java b/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java deleted file mode 100644 index b5ac5584..00000000 --- a/src/main/java/se/isselab/HAnS/trafficLight/HansTrafficLightWidget.java +++ /dev/null @@ -1,223 +0,0 @@ -package se.isselab.HAnS.trafficLight; - -import com.intellij.notification.Notification; -import com.intellij.notification.NotificationType; -import com.intellij.notification.Notifications; -import com.intellij.openapi.actionSystem.*; -import com.intellij.openapi.actionSystem.ex.ActionButtonLook; -import com.intellij.openapi.actionSystem.ex.ActionUtil; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.colors.ColorKey; -import com.intellij.openapi.editor.ex.util.EditorUtil; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; -import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.ui.JBColor; -import com.intellij.ui.scale.JBUIScale; -import com.intellij.util.ui.JBInsets; -import com.intellij.util.ui.JBUI; -import com.intellij.util.ui.UIUtil; -import kotlinx.html.P; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import se.isselab.HAnS.AnnotationIcons; -import se.isselab.HAnS.featureLocation.FeatureFileMapping; -import se.isselab.HAnS.featureModel.psi.FeatureModelFeature; -import se.isselab.HAnS.pluginExtensions.backgroundTasks.featureFileMappingTasks.FeatureFileMappingCallback; -import se.isselab.HAnS.pluginExtensions.backgroundTasks.featureFileMappingTasks.GetFeatureFileMappings; - -import javax.swing.*; -import javax.swing.border.Border; -import javax.swing.plaf.FontUIResource; -import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.io.File; -import java.util.HashSet; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -// &begin[WidgetLocation] -public class HansTrafficLightWidget extends JPanel { - private AnAction action; - private Presentation presentation; - private MouseListener mouseListener; - private boolean mousePressed = false; - private boolean mouseHover = false; - private JLabel hansIcon; - private Editor editor; - private String place; - private String filePath; - - HansTrafficLightWidget(AnAction action, Presentation presentation, - String place, Editor editor){ - this.action = action; - this.presentation = presentation; - this.place = place; - this.editor = editor; - setOpaque(false); - // &begin[WidgetStyle] - hansIcon = new JLabel(); - - if (!SystemInfo.isWindows) { - hansIcon.setFont(new FontUIResource(getFont().deriveFont(getFont().getStyle(), - (float) (getFont().getSize() - JBUIScale.scale(2))))); - } - - hansIcon.setForeground(new JBColor( - Objects.requireNonNull(editor.getColorsScheme().getColor(ColorKey.createColorKey("ActionButton.iconTextForeground", - UIUtil.getContextHelpForeground()))), - ColorKey.createColorKey("ActionButton.iconTextForeground", UIUtil.getContextHelpForeground()).getDefaultColor() - )); - - hansIcon.setIcon(AnnotationIcons.PluginIcon); - // &end[WidgetStyle] - hansIcon.setVisible(false); - - searchFeatures(); - - add(hansIcon); - // &begin[ClickAndHover] - mouseListener = new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - mousePressed = true; - if (hansIcon.isVisible()) { - repaint(); - } - - } - - @Override - public void mouseReleased(MouseEvent e) { - var context = ActionToolbar.getDataContextFor(HansTrafficLightWidget.this); - var event = AnActionEvent.createFromInputEvent(e, place, presentation, context, false, true); - ActionUtil.performActionDumbAwareWithCallbacks(action, event); - mousePressed = false; - if (hansIcon.isVisible()) { - repaint(); - openMappingsFile(); - } - } - - @Override - public void mouseEntered(MouseEvent e) { - mouseHover = true; - if (hansIcon.isVisible()){ - repaint(); - showPopupWithMappingName(); - } - - } - - @Override - public void mouseExited(MouseEvent e) { - mouseHover = false; - if (hansIcon.isVisible()){ - repaint(); - } - } - }; - - setBorder(new Border() { - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - // Empty border - } - - @Override - public Insets getBorderInsets(Component c) { - return JBUI.insets(0, 2); - } - - @Override - public boolean isBorderOpaque() { - return false; - } - }); - - if (editor.getProject() != null) { - var disposable = Disposer.newDisposable(); - EditorUtil.disposeWithEditor(editor, disposable); - } - // &end[ClickAndHover] - } - // &begin[SearchFeatures] - private void searchFeatures() { - new GetFeatureFileMappings(this.editor.getProject(), "Find Feature File Mappings", new FeatureFileMappingCallback() { - @Override - public void onComplete(Map featureFileMappings) { - Set> vals = new HashSet<>(); - featureFileMappings.forEach((key, value) -> { - var res = value.getFileMappings(); - if (!res.isEmpty()) { - vals.add(res); - } - }); - for (Set val : vals) { - for (String key : val) { - if (key.contains(editor.getVirtualFile().getPath())){ - filePath = key.substring(key.indexOf(":")+1); - hansIcon.setVisible(true); - } - } - } - } - }).queue(); - } - // &end[SearchFeatures] - - @Override - public void removeNotify() { - removeMouseListener(mouseListener); - } - - @Override - public void addNotify() { - super.addNotify(); - addMouseListener(mouseListener); - } - // &begin[HoverPopupStyle] - private void showPopupWithMappingName() { - Notification notification = new Notification( - "notification", - "Mapped feature file", - filePath, - NotificationType.INFORMATION - ); - Notifications.Bus.notify(notification); - } - // &end[HoverPopupStyle] - private void openMappingsFile() { - VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(new File(filePath)); - if (virtualFile != null && this.editor.getProject() != null) { - FileEditorManager.getInstance(this.editor.getProject()).openFile(virtualFile, true); - } else { - JOptionPane.showMessageDialog(null, "File not found: " + filePath); - } - } - // &begin[WidgetStyle] - @Override - protected void paintComponent(Graphics graphics) { - if (filePath == null) return; - int state = mousePressed ? ActionButtonComponent.PUSHED - : mouseHover ? ActionButtonComponent.POPPED - : ActionButtonComponent.NORMAL; - if (state == ActionButtonComponent.NORMAL) return; - - var rect = new Rectangle(getSize()); - JBInsets.removeFrom(rect, JBUI.insets(2)); - - Color color = (state == ActionButtonComponent.PUSHED) - ? JBUI.CurrentTheme.ActionButton.pressedBackground() - : JBUI.CurrentTheme.ActionButton.hoverBackground(); - - ActionButtonLook.SYSTEM_LOOK.paintLookBackground(graphics, rect, color); - } - // &end[WidgetStyle] -} -// &end[WidgetLocation]