diff --git a/README.md b/README.md index 1657e9a..42a8b29 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,76 @@ -# P ≠ NP: Connell Super-Complexity Method (2025) - -## Abstract -Formal proof of P ≠ NP using the Connell Super-Complexity Method, verified with Coq formalization and supplemental experimental analysis. - -## Structure -- /Paper/ — Full LaTeX/PDF paper -- /CoqFormalization/ — Coq project proving P ≠ NP -- /SupplementaryExperiments/ — Python experimental scripts - -## Reproducibility -All Coq proofs verifiable using Coq 8.17+. -Python experiments require Python 3.10+. - -License: MIT +# plang IDE + +plang IDE is a lightweight, user-friendly integrated development environment designed specifically for the plang language. It offers a clean interface, robust code editing features, and a range of tools to enhance the development experience. + +--- + +## Features + +- **Code Editing with Syntax Highlighting**: + Edit plang scripts with full syntax highlighting, line numbering, and basic code formatting features. + +- **File Management**: + Open, save, and organize your plang projects with an integrated file manager. + +- **Integrated Runner**: + Run your plang code directly from the IDE and view the output in a built-in console. No need for external terminals. + +- **Debugging Tools**: + Set breakpoints, step through code line-by-line, and inspect variables to identify and fix issues quickly. + +- **Customizable Settings**: + Tailor your development environment by adjusting font sizes, themes, and tab widths to suit your preferences. + +- **Code Examples**: + Access a library of sample plang scripts and example workflows to help you learn and experiment. + +--- + +## Getting Started + +1. **Installation**: + Make sure you have Python 3.9+ installed on your system. Clone this repository and run the following command to install dependencies: + ```bash + pip install -r requirements.txt +Launching the IDE: +To start the IDE, run: + +bash +Copy +python plang_ide.py +The graphical interface will launch, allowing you to open and edit plang scripts. + +Opening a File: + +Use the File > Open menu to open an existing plang script. +Make changes and save your work using File > Save or File > Save As. +Running Your Code: + +Click the Run button in the toolbar or select Run > Execute from the menu. +The output will appear in the console panel at the bottom of the IDE. +Debugging: + +To set a breakpoint, click on the gutter next to the line you wish to pause. +Use the Debug > Step Over or Debug > Step Into menu options to control execution. +Inspect variable values in the variables pane to understand the program’s state. +Customizing Settings: + +Adjust font size and theme under Settings > Preferences. +Set your preferred tab width and other code style options. +Included Components +Editor: Syntax-highlighted text editor with line numbers. +Runner: Execute plang scripts directly and view output in the integrated console. +Debugger: Debugging features like breakpoints and variable inspection. +File Manager: Intuitive tools for opening, saving, and managing project files. +Examples: A library of sample scripts and coding patterns for reference. +Settings: A configuration system to customize your development environment. +Example Projects +Browse the Examples tab in the IDE to find sample plang scripts. These examples demonstrate common patterns and best practices. Use them as starting points for your own projects or to learn how different language constructs work. + +Contributing +We welcome contributions! If you encounter any issues or have ideas for improvements: + +Fork this repository. +Create a new branch (git checkout -b feature-name). +Make your changes and test them thoroughly. +Submit a pull request, describing the purpose of the changes. diff --git a/debugger.py b/debugger.py new file mode 100644 index 0000000..9626c70 --- /dev/null +++ b/debugger.py @@ -0,0 +1,24 @@ +class Debugger: + def __init__(self): + self.breakpoints = set() + + def add_breakpoint(self, line_number): + self.breakpoints.add(line_number) + + def remove_breakpoint(self, line_number): + self.breakpoints.discard(line_number) + + def clear_breakpoints(self): + self.breakpoints.clear() + + def step_over(self): + # Stub for stepping over a line in the debugger + pass + + def step_into(self): + # Stub for stepping into a function call + pass + + def step_out(self): + # Stub for stepping out of the current function + pass diff --git a/editor.py b/editor.py new file mode 100644 index 0000000..e3e31a1 --- /dev/null +++ b/editor.py @@ -0,0 +1,23 @@ +from PyQt5.QtWidgets import QTextEdit +from PyQt5.QtGui import QTextCursor, QTextFormat +from PyQt5.QtCore import Qt + +class CodeEditor(QTextEdit): + def __init__(self, parent=None): + super().__init__(parent) + self.line_numbers = True + self.init_ui() + + def init_ui(self): + # Setup the font and general style of the code editor + self.setFontFamily("Courier") + self.setFontPointSize(10) + self.setTabStopDistance(4 * self.fontMetrics().horizontalAdvance(' ')) + + def highlight_syntax(self, block): + # Stub for adding syntax highlighting rules + pass + + def update_line_numbers(self): + # Handle showing line numbers if needed + pass diff --git a/examples.py b/examples.py new file mode 100644 index 0000000..96e340b --- /dev/null +++ b/examples.py @@ -0,0 +1,24 @@ +def get_examples(): + return [ + { + "name": "Hello World", + "code": 'print("Hello, world!")' + }, + { + "name": "Basic Loop", + "code": """ +for i in range(10): + print("Number:", i) +""" + }, + { + "name": "Simple Function", + "code": """ +def add_numbers(a, b): + return a + b + +result = add_numbers(3, 5) +print("Result:", result) +""" + } + ] diff --git a/file_manager.py b/file_manager.py new file mode 100644 index 0000000..f943900 --- /dev/null +++ b/file_manager.py @@ -0,0 +1,19 @@ +from pathlib import Path + +class FileManager: + def __init__(self): + self.current_file_path = None + + def open_file(self, path): + self.current_file_path = Path(path) + with open(path, 'r') as file: + return file.read() + + def save_file(self, content): + if self.current_file_path: + with open(self.current_file_path, 'w') as file: + file.write(content) + + def save_as(self, path, content): + self.current_file_path = Path(path) + self.save_file(content) diff --git a/plang_ide.py b/plang_ide.py new file mode 100644 index 0000000..da3effb --- /dev/null +++ b/plang_ide.py @@ -0,0 +1,214 @@ +import sys +from PyQt5.QtWidgets import ( + QApplication, QMainWindow, QPlainTextEdit, QVBoxLayout, QWidget, + QFileDialog, QPushButton, QHBoxLayout, QLabel, QTextEdit +) +from PyQt5.QtGui import QFont, QColor, QTextCharFormat, QPainter +from PyQt5.QtCore import Qt, QRect + +class LineNumberArea(QWidget): + def __init__(self, editor): + super().__init__(editor) + self.editor = editor + + def sizeHint(self): + return self.editor.lineNumberAreaWidth(), 0 + + def paintEvent(self, event): + self.editor.lineNumberAreaPaintEvent(event) + +class SyntaxHighlighter: + def __init__(self, editor): + self.editor = editor + self.setup_rules() + + def setup_rules(self): + self.rules = [] + keyword_format = QTextCharFormat() + keyword_format.setForeground(QColor("blue")) + keywords = [ + "def", "class", "if", "else", "elif", "for", "while", "return", + "import", "from", "as", "try", "except", "finally", "with", "yield", + "assert", "del", "global", "nonlocal", "pass", "raise" + ] + for keyword in keywords: + self.rules.append((keyword, keyword_format)) + + def highlight(self): + cursor = self.editor.textCursor() + cursor.movePosition(cursor.Start) + document = self.editor.document() + block_count = document.blockCount() + for i in range(block_count): + block = document.findBlockByNumber(i) + block_text = block.text() + for pattern, fmt in self.rules: + start_idx = block_text.find(pattern) + if start_idx >= 0: + cursor.setPosition(block.position() + start_idx) + cursor.movePosition(cursor.Right, cursor.KeepAnchor, len(pattern)) + cursor.mergeCharFormat(fmt) + +class PlangEditor(QPlainTextEdit): + def __init__(self, parent=None): + super().__init__(parent) + self.lineNumberArea = LineNumberArea(self) + self.highlighter = SyntaxHighlighter(self) + self.updateLineNumberAreaWidth(0) + self.cursorPositionChanged.connect(self.highlightCurrentLine) + + def lineNumberAreaWidth(self): + digits = len(str(self.blockCount())) + return 3 + self.fontMetrics().horizontalAdvance('9') * digits + + def updateLineNumberAreaWidth(self, _): + self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0) + + def resizeEvent(self, event): + super().resizeEvent(event) + cr = self.contentsRect() + self.lineNumberArea.setGeometry(QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height())) + + def highlightCurrentLine(self): + extra_selections = [] + selection = QTextEdit.ExtraSelection() + + line_color = QColor(Qt.yellow).lighter(160) + selection.format.setBackground(line_color) + selection.format.setProperty(QTextCharFormat.FullWidthSelection, True) + selection.cursor = self.textCursor() + selection.cursor.clearSelection() + extra_selections.append(selection) + self.setExtraSelections(extra_selections) + + def lineNumberAreaPaintEvent(self, event): + painter = QPainter(self.lineNumberArea) + painter.fillRect(event.rect(), Qt.lightGray) + + block = self.firstVisibleBlock() + block_number = block.blockNumber() + top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top() + bottom = top + self.blockBoundingRect(block).height() + + while block.isValid() and top <= event.rect().bottom(): + if block.isVisible() and bottom >= event.rect().top(): + number = str(block_number + 1) + rect = QRect(0, int(top), self.lineNumberArea.width(), self.fontMetrics().height()) + painter.setPen(Qt.black) + painter.drawText(rect, Qt.AlignRight, number) + block = block.next() + top = bottom + bottom = top + self.blockBoundingRect(block).height() + block_number += 1 + +class PlangIDE(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("Plang IDE") + self.setGeometry(100, 100, 800, 600) + + # Set up main editor where user writes code + self.editor = PlangEditor(self) + self.editor.setFont(QFont("Courier", 10)) + + # Set up output console for showing run results or debug logs + self.output_console = QTextEdit(self) + self.output_console.setReadOnly(True) + + # Run button to execute the code + self.run_button = QPushButton("Run", self) + self.run_button.clicked.connect(self.run_code) + + # Open and Save buttons for file management + self.open_button = QPushButton("Open", self) + self.open_button.clicked.connect(self.open_file) + self.save_button = QPushButton("Save", self) + self.save_button.clicked.connect(self.save_file) + + # Setup UI layout + self.setup_layout() + + def setup_layout(self): + """ + Defines the layout of the main window including editor, buttons, and console. + """ + # Buttons row + buttons_layout = QHBoxLayout() + buttons_layout.addWidget(self.open_button) + buttons_layout.addWidget(self.save_button) + buttons_layout.addWidget(self.run_button) + + # Main vertical layout + main_layout = QVBoxLayout() + main_layout.addLayout(buttons_layout) + main_layout.addWidget(QLabel("Code Editor:")) + main_layout.addWidget(self.editor) + main_layout.addWidget(QLabel("Console Output:")) + main_layout.addWidget(self.output_console) + + # Create a central widget to hold the layout + container = QWidget() + container.setLayout(main_layout) + self.setCentralWidget(container) + + def open_file(self): + """ + Opens a file dialog to select and read a Python file into the editor. + """ + filepath, _ = QFileDialog.getOpenFileName( + self, "Open Python File", "", "Python Files (*.py)" + ) + if filepath: + try: + with open(filepath, 'r') as file: + self.editor.setPlainText(file.read()) + except Exception as e: + self.output_console.append(f"Error opening file: {e}") + + def save_file(self): + """ + Opens a file dialog to select a path and saves the editor content to that file. + """ + filepath, _ = QFileDialog.getSaveFileName( + self, "Save Python File", "", "Python Files (*.py)" + ) + if filepath: + try: + with open(filepath, 'w') as file: + file.write(self.editor.toPlainText()) + self.output_console.append("File saved successfully.") + except Exception as e: + self.output_console.append(f"Error saving file: {e}") + + def run_code(self): + """ + Executes the code entered in the editor and prints the output in the console. + """ + code = self.editor.toPlainText() + self.output_console.clear() + self.output_console.append("---- Running Code ----") + + # Redirect stdout and stderr to capture output + import io + import contextlib + + output = io.StringIO() + error = io.StringIO() + + try: + with contextlib.redirect_stdout(output), contextlib.redirect_stderr(error): + exec(code, {}) + self.output_console.append(output.getvalue()) + except Exception as e: + self.output_console.append(f"Error: {str(e)}") + finally: + output.close() + error.close() + + self.output_console.append("---- Execution Finished ----") + +if __name__ == '__main__': + app = QApplication(sys.argv) + ide = PlangIDE() + ide.show() + sys.exit(app.exec_()) diff --git a/runner.py b/runner.py new file mode 100644 index 0000000..9f583c9 --- /dev/null +++ b/runner.py @@ -0,0 +1,30 @@ +import subprocess +import sys + +class CodeRunner: + def __init__(self): + self.current_process = None + + def run_code(self, code): + """ + Runs the given code string in a subprocess. + """ + if self.current_process: + self.stop_running_code() + + self.current_process = subprocess.Popen( + [sys.executable, '-c', code], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + def read_output(self): + if self.current_process: + out, err = self.current_process.communicate() + return out, err + + def stop_running_code(self): + if self.current_process: + self.current_process.terminate() + self.current_process = None diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..17fbd8c --- /dev/null +++ b/settings.py @@ -0,0 +1,13 @@ +class Settings: + def __init__(self): + self.preferences = { + "font_size": 10, + "theme": "light", + "tab_width": 4 + } + + def get(self, key, default=None): + return self.preferences.get(key, default) + + def set(self, key, value): + self.preferences[key] = value