implemend a simple webeditor for prolog
All checks were successful
Build, Publish Docker Image, and Deploy to Kubernetes / build_and_push (push) Successful in 6s
Build, Publish Docker Image, and Deploy to Kubernetes / deploy_to_k8s (push) Successful in 11s

This commit is contained in:
Jonas Hinterdorfer 2025-03-17 13:13:08 +01:00
parent fca3c538d6
commit 5a5bae2e92
2 changed files with 549 additions and 0 deletions

15
Dockerfile Normal file
View File

@ -0,0 +1,15 @@
# Use an official Nginx image as the base image
FROM nginx:alpine
# Set the working directory inside the container
WORKDIR /usr/share/nginx/html
# Copy the index.html and adventure.pl files into the Nginx directory
COPY index.html /usr/share/nginx/html/
# Expose port 80 to allow access to the web server
EXPOSE 80
# Start the Nginx server
CMD ["nginx", "-g", "daemon off;"]

534
index.html Normal file
View File

@ -0,0 +1,534 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prolog Editor and Console</title>
<!-- Add Tau Prolog library -->
<script src="https://cdn.jsdelivr.net/npm/tau-prolog"></script>
<!-- Add CodeMirror for syntax highlighting and autocomplete -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/theme/monokai.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/mode/prolog/prolog.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/addon/hint/show-hint.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/addon/hint/show-hint.min.css"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.2/addon/edit/closebrackets.min.js"></script>
<style>
body {
font-family: 'Courier New', monospace;
background-color: #1e1e1e;
color: #f0f0f0;
margin: 0;
padding: 0;
height: 100vh;
display: flex;
flex-direction: column;
}
header {
background-color: #333;
color: #00ff00;
padding: 10px 20px;
text-align: center;
}
.container {
display: flex;
flex-grow: 1;
padding: 10px;
gap: 10px;
height: calc(100vh - 120px);
}
.editor-section {
flex: 1;
display: flex;
flex-direction: column;
}
.console-section {
flex: 1;
display: flex;
flex-direction: column;
}
.CodeMirror {
height: 100%;
font-size: 16px;
border-radius: 5px;
}
#console {
background-color: #000;
color: #00ff00;
border: 1px solid #444;
border-radius: 5px;
padding: 10px;
overflow-y: auto;
flex-grow: 1;
white-space: pre-wrap;
font-size: 16px;
max-height: calc(100vh - 220px);
margin-bottom: 10px;
}
.input-area {
display: flex;
margin-bottom: 10px;
}
#prompt {
color: #00ff00;
margin-right: 5px;
font-size: 16px;
}
#command-input {
flex-grow: 1;
background-color: #000;
color: #00ff00;
border: none;
outline: none;
font-family: 'Courier New', monospace;
font-size: 16px;
padding: 5px;
}
.controls {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
button {
background-color: #444;
color: #00ff00;
border: 1px solid #00ff00;
border-radius: 3px;
padding: 8px 15px;
cursor: pointer;
font-family: 'Courier New', monospace;
}
button:hover {
background-color: #555;
}
.status {
color: #aaa;
margin-bottom: 10px;
}
.section-title {
margin-top: 0;
margin-bottom: 10px;
color: #00ff00;
}
.file-controls {
display: flex;
gap: 10px;
margin-bottom: 10px;
}
input[type="file"] {
display: none;
}
.file-upload-label {
background-color: #444;
color: #00ff00;
border: 1px solid #00ff00;
border-radius: 3px;
padding: 8px 15px;
cursor: pointer;
display: inline-block;
font-family: 'Courier New', monospace;
}
.file-upload-label:hover {
background-color: #555;
}
</style>
</head>
<body>
<header>
<h1>Prolog Editor and Console</h1>
</header>
<div class="container">
<!-- Editor Section -->
<div class="editor-section">
<h2 class="section-title">Editor</h2>
<div class="file-controls">
<input type="file" id="file-upload" accept=".pl">
<label for="file-upload" class="file-upload-label">Upload Prolog File</label>
<button id="save-button">Download File</button>
<button id="run-button">Run Program</button>
<button id="clear-editor-button">Clear Editor</button>
</div>
<textarea id="editor"></textarea>
</div>
<!-- Console Section -->
<div class="console-section">
<h2 class="section-title">Console</h2>
<div class="status" id="status">Ready to load Prolog program</div>
<div class="controls">
<button id="clear-console-button">Clear Console</button>
<button id="reset-session-button">Reset Session</button>
</div>
<div id="console">Welcome to the Prolog Console!
System initialized and ready.
</div>
<div class="input-area">
<span id="prompt">?- </span>
<input type="text" id="command-input" placeholder="Enter Prolog query" disabled>
</div>
</div>
</div>
<script>
// DOM elements
const editor = document.getElementById('editor');
const consoleOutput = document.getElementById('console');
const commandInput = document.getElementById('command-input');
const statusElement = document.getElementById('status');
const fileUpload = document.getElementById('file-upload');
const saveButton = document.getElementById('save-button');
const runButton = document.getElementById('run-button');
const clearEditorButton = document.getElementById('clear-editor-button');
const clearConsoleButton = document.getElementById('clear-console-button');
const resetSessionButton = document.getElementById('reset-session-button');
// Tau Prolog session
let session = null;
let programLoaded = false;
// CodeMirror setup
let codeMirror = CodeMirror.fromTextArea(editor, {
mode: 'prolog',
theme: 'monokai',
lineNumbers: true,
autoCloseBrackets: true,
matchBrackets: true,
indentUnit: 4,
tabSize: 4,
indentWithTabs: true,
extraKeys: {
"Ctrl-Space": "autocomplete"
}
});
// Set initial sample content
codeMirror.setValue(`% Prolog program example
% You can edit this or upload your own file
% Simple facts
likes(john, pizza).
likes(mary, pasta).
likes(bob, burger).
likes(alice, pizza).
% Rule to find who likes the same food
same_taste(Person1, Person2) :-
likes(Person1, Food),
likes(Person2, Food),
Person1 \\= Person2.
% Try queries like:
% likes(john, pizza).
% likes(X, pizza).
% same_taste(john, X).
`);
// Check if Tau Prolog is loaded
function checkTauProlog() {
if (typeof pl === 'undefined') {
addToConsole("Error: Tau Prolog library not loaded!");
addToConsole("Trying to load Tau Prolog dynamically...");
// Try to load Tau Prolog dynamically
const script = document.createElement('script');
script.src = "https://cdnjs.cloudflare.com/ajax/libs/tau-prolog/0.3.4/tau-prolog.min.js";
script.onload = function() {
addToConsole("Tau Prolog loaded successfully!");
initPrologSession();
};
script.onerror = function() {
addToConsole("Failed to load Tau Prolog library. Please check your internet connection.");
statusElement.textContent = "Error: Could not load Tau Prolog library";
};
document.body.appendChild(script);
return false;
}
return true;
}
// Initialize Prolog session
function initPrologSession() {
if (!checkTauProlog()) {
return; // Wait for dynamic loading
}
try {
session = pl.create();
addToConsole("Prolog engine initialized successfully.");
statusElement.textContent = "Prolog engine ready. Edit code and click 'Run Program'";
} catch (error) {
addToConsole("Error initializing Prolog engine: " + error.message);
console.error("Error initializing Prolog engine:", error);
}
}
// Add text to console
function addToConsole(text) {
consoleOutput.textContent += "\n" + text;
consoleOutput.scrollTop = consoleOutput.scrollHeight;
}
// Clear console
function clearConsole() {
consoleOutput.textContent = "Console cleared.";
}
// Load Prolog program from editor
function loadProgramFromEditor() {
const programContent = codeMirror.getValue();
if (!programContent || programContent.trim() === "") {
addToConsole("Error: Editor is empty. Please add some Prolog code.");
return;
}
if (!checkTauProlog()) {
addToConsole("Cannot load program: Tau Prolog library not available.");
return;
}
addToConsole("Loading program into Prolog engine...");
try {
// Reset session to clean state
session = pl.create();
session.consult(programContent, {
success: function() {
programLoaded = true;
statusElement.textContent = "Program loaded and ready. Type your Prolog queries below.";
addToConsole("Program loaded successfully!");
addToConsole("Type your Prolog queries in the command line below.");
commandInput.disabled = false;
commandInput.focus();
},
error: function(err) {
statusElement.textContent = "Error loading program: " + err;
addToConsole("Error loading program: " + err);
addToConsole("This might be due to syntax errors in your Prolog code.");
// Try to provide more helpful error information
const errorLines = err.toString().split('\n');
if (errorLines.length > 1) {
addToConsole("\nError details:");
errorLines.forEach(line => {
addToConsole("- " + line);
});
}
}
});
} catch (error) {
addToConsole("Error in program loading: " + error.message);
console.error("Error in program loading:", error);
}
}
// Execute Prolog query
function executeQuery(query) {
if (!programLoaded) {
addToConsole("Error: Please load a program first.");
return;
}
addToConsole("?- " + query);
try {
session.query(query, {
success: function(goal) {
session.answer({
success: function(answer) {
if (answer === false) {
addToConsole("false.");
} else if (pl.type.is_substitution(answer)) {
let vars = Object.keys(answer.links);
if (vars.length === 0) {
addToConsole("true.");
} else {
let result = "";
for (let i = 0; i < vars.length; i++) {
result += vars[i] + " = " + answer.links[vars[i]] + (i < vars.length - 1 ? ",\n" : "");
}
addToConsole(result + ".");
}
// Check for more answers
moreAnswers();
}
},
error: function(err) {
addToConsole("Error: " + err);
},
fail: function() {
addToConsole("false.");
},
limit: function() {
addToConsole("Limit exceeded.");
}
});
},
error: function(err) {
addToConsole("Error: " + err);
}
});
} catch (error) {
addToConsole("Error executing query: " + error.message);
console.error("Error executing query:", error);
}
}
// Check for more answers
function moreAnswers() {
try {
session.answer({
success: function(answer) {
if (answer === false) {
// No more answers
} else if (pl.type.is_substitution(answer)) {
let vars = Object.keys(answer.links);
if (vars.length === 0) {
addToConsole("true ;");
} else {
let result = "";
for (let i = 0; i < vars.length; i++) {
result += vars[i] + " = " + answer.links[vars[i]] + (i < vars.length - 1 ? ",\n" : "");
}
addToConsole(result + " ;");
}
// Check for more answers
moreAnswers();
}
},
error: function(err) {
addToConsole("Error: " + err);
},
fail: function() {
// No more answers
},
limit: function() {
addToConsole("Limit exceeded.");
}
});
} catch (error) {
addToConsole("Error checking for more answers: " + error.message);
}
}
// File upload handler
fileUpload.addEventListener('change', function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
codeMirror.setValue(e.target.result);
addToConsole(`File "${file.name}" loaded into editor.`);
};
reader.onerror = function(e) {
addToConsole("Error reading file: " + e.target.error);
};
reader.readAsText(file);
});
// Save (download) button handler
saveButton.addEventListener('click', function() {
const content = codeMirror.getValue();
if (!content || content.trim() === "") {
addToConsole("Error: Editor is empty. Nothing to download.");
return;
}
const blob = new Blob([content], {type: 'text/plain'});
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'program.pl';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(a.href);
addToConsole("File downloaded as 'program.pl'");
});
// Run program button handler
runButton.addEventListener('click', function() {
loadProgramFromEditor();
});
// Clear editor button handler
clearEditorButton.addEventListener('click', function() {
codeMirror.setValue('');
addToConsole("Editor cleared.");
});
// Clear console button handler
clearConsoleButton.addEventListener('click', clearConsole);
// Reset session button handler
resetSessionButton.addEventListener('click', function() {
programLoaded = false;
commandInput.disabled = true;
try {
if (typeof pl !== 'undefined') {
session = pl.create();
addToConsole("Prolog session reset.");
statusElement.textContent = "Session reset. Click 'Run Program' to load your code.";
} else {
addToConsole("Error: Tau Prolog library not available.");
checkTauProlog();
}
} catch (error) {
addToConsole("Error resetting Prolog engine: " + error.message);
console.error("Error resetting Prolog engine:", error);
}
});
// Command input handler
commandInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter') {
const query = commandInput.value.trim();
if (query) {
executeQuery(query);
commandInput.value = '';
}
}
});
// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
// Wait a moment to ensure scripts are loaded
setTimeout(initPrologSession, 300);
});
// Initialize immediately as well (in case DOMContentLoaded already fired)
initPrologSession();
</script>
</body>
</html>