This commit is contained in:
dennisgunia
2021-02-02 23:12:52 +01:00
commit 738579d7fc
16 changed files with 882 additions and 0 deletions

59
outfile.info Normal file
View File

@@ -0,0 +1,59 @@
################################################################################
_ _ _ _
/ \ _ __ ___(_) |__ | | ___
/ _ \ | '_ \/ __| | '_ \| |/ _ \
/ ___ \| | | \__ \ | |_) | | __/
/_/ \_\_| |_|___/_|_.__/|_|\___|
Title : Testdokument
Author : Dennis Gunia
################################################################################
Inhalt:
=======
1. Kapitel1
-----------
1.1 Hier gehts weiter
1.2 Hier gehts weiter Pt. 2
2. Kapitel2
-----------
3. Kapitel3
-----------
3.1 Hier gehts weiter Pt. 2
################################################################################
1. Kapitel1
===========
Dies ist ein Testdokument
1.1 Hier gehts weiter
---------------------
Wenn der Kühler friert, der Keilriemen durchhängt und Schläuche nicht ganz dicht sind,
kann es dem Motor ganz schön heiß werden. Damit Ihnen Ihr Motor bei Kälte keine Kopfschmerzen bereitet,
sollten Sie Ihr Kühlsystem zum günstigen Komplett-Preis durchchecken lassen.
Ihr Opel-Händler nimmt dabei alle Kühlmittel- und Heizungsschläuche, den Kühler samt ...
1.2 Hier gehts weiter Pt. 2
---------------------------
ur wer seinen Visionen vertraut, kann die Wirklichkeit verändern. Denn Visionen sind es, die uns weiterbringen.
Visionen sind es, die uns und unseren Kunden zu einem wirklichen Wettbewerbsvorsprung verhelfen und neue Perspektiven erschließen.
2. Kapitel2
===========
Dies ist ein Testdokument
3. Kapitel3
===========
Dies ist ein Testdokument
3.1 Hier gehts weiter Pt. 2
---------------------------
wieso?

17
primalmarkup-lang/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,17 @@
// A launch configuration that launches the extension inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
]
}
]
}

View File

@@ -0,0 +1,4 @@
.vscode/**
.vscode-test/**
.gitignore
vsc-extension-quickstart.md

View File

@@ -0,0 +1,9 @@
# Change Log
All notable changes to the "primalmarkup-lang" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

View File

@@ -0,0 +1,65 @@
# primalmarkup-lang README
This is the README for your extension "primalmarkup-lang". After writing up a brief description, we recommend including the following sections.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: enable/disable this extension
* `myExtension.thing`: set to `blah` to do something
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
-----------------------------------------------------------------------------------------------------------
## Working with Markdown
**Note:** You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux)
* Toggle preview (`Shift+CMD+V` on macOS or `Shift+Ctrl+V` on Windows and Linux)
* Press `Ctrl+Space` (Windows, Linux) or `Cmd+Space` (macOS) to see a list of Markdown snippets
### For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

View File

@@ -0,0 +1,22 @@
{
"comments": {
// symbol used for single line comment. Remove this entry if your language does not support line comments
"lineComment": "%%",
},
// symbols used as brackets
"brackets": [
["{{", "}}"],
["[[", "]]"]
],
// symbols that are auto closed when typing
"autoClosingPairs": [
["{{", "}}"],
["[[", "]]"]
],
// symbols that can be used to surround a selection
"surroundingPairs": [
["{{", "}}"],
["[[", "]]"]
]
}

View File

@@ -0,0 +1,25 @@
{
"name": "primalmarkup-lang",
"displayName": "primalmarkup-lang",
"description": "PrimalMarkup Language Syntax",
"version": "0.0.1",
"engines": {
"vscode": "^1.52.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [{
"id": "pms",
"aliases": ["PrimalMarkupScript", "pms"],
"extensions": [".pml",".pms",".pmc1",".pmc2",".pml"],
"configuration": "./language-configuration.json"
}],
"grammars": [{
"language": "pms",
"scopeName": "pm",
"path": "./syntaxes/pms.tmLanguage.json"
}]
}
}

View File

@@ -0,0 +1,79 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "PrimalMarkupScript",
"patterns": [
{
"include": "#object"
},
{
"include": "#comments"
},
{
"include": "#metatag"
}
],
"repository": {
"object": {
"patterns": [
{
"match": "^\\[\\[([\\w\\d._]*)\\=([\\w\\d\\-\\\":;,._$%&\/\\\\ ]*)\\]\\]$",
"captures": {
"0":{
"name": "support.type.exception.python"
},
"1": {
"name": "support.type.property-name.json"
},
"2": {
"name": "string.quoted.double.json"
}
},
"name": "punctuation.definition.string.end.json"
},
{
"match": "^\\{\\{([\\w\\d._]*)\\=([\\w\\d\\-\\\":;,._$%&\/\\\\ ]*)\\}\\}$",
"captures": {
"0":{
"name": "support.type.exception.python"
},
"1": {
"name": "keyword.control.flow.python"
},
"2": {
"name": "string.quoted.double.json"
},
"3": {
"name": "comment.block.empty.java"
}
},
"name": "punctuation.definition.string.end.json"
},
{
"match": "^\\{\\{([\\w\\d._]*)\\}\\}$",
"captures": {
"0":{
"name": "support.type.exception.python"
},
"1": {
"name": "keyword.control.flow.python"
}
},
"name": "punctuation.definition.string.end.json"
}
]
},
"comments": {
"patterns": [{
"name": "comment.line.as",
"match": "(\\%\\%).*$\\n?",
"captures": {
"1": {
"name": "comment.line.double-slash.js"
}
}
}]
}
},
"scopeName": "pm"
}

View File

@@ -0,0 +1,29 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension.
* `syntaxes/pms.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization.
* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets.
## Get up and running straight away
* Make sure the language configuration settings in `language-configuration.json` are accurate.
* Press `F5` to open a new window with your extension loaded.
* Create a new file with a file name suffix matching your language.
* Verify that syntax highlighting works and that the language configuration settings are working.
## Make changes
* You can relaunch the extension from the debug toolbar after making changes to the files listed above.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Add more language features
* To add features such as intellisense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs
## Install your extension
* To start using your extension with Visual Studio Code copy it into the `<user home>/.vscode/extensions` folder and restart Code.
* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.

148
readme.md Normal file
View File

@@ -0,0 +1,148 @@
____ _ _ __ __ _
| _ \ _ __(_)_ __ ___ __ _| | \/ | __ _ _ __| | ___ _ _ __
| |_) | '__| | '_ ` _ \ / _` | | |\/| |/ _` | '__| |/ / | | | '_ \
| __/| | | | | | | | | (_| | | | | | (_| | | | <| |_| | |_) |
|_| |_| |_|_| |_| |_|\__,_|_|_| |_|\__,_|_| |_|\_\\__,_| .__/
|_|
# PrimalMarkup
The name already implies everything. PrimalMarkup is probably the worst Markup-Language out there. Please do yourself a favor and don't look at the source-code. This project has been done in a hurry!
PrimalMarkupScript was originally designed to easily add a content table and chapter-numbers to text files. This is achieved by 'compiling' .pms (Primal-Markup-Script-File) into plain text files. Chapter-numbering and indentation as well as generating the table of contents is handled by the compiler.
As of now, the compiler supports two levels of headlines.
# Files
PrimalMarkupScript uses the .pms extension for its sourcefiles. The Repository also contains the complementary VS-Code plugin for syntax highlighting.
Temporary files are created in /tmp and have the suffix .pmc1
## Syntax
The PrimalMarkupScript-Language conatins three basic elements:
- Comments (of course...)
- Metadata Tags
- Content-Tags
### Comments
Comments are single-lined and start with `%% `. Inline Comments are not supported.
It is recommended to remove any preceding white-spaces to avoid bugs.
### Metadata Tags
Metadata Tags set options for the current scope. Right now,there is only one scope available:
- Document
All Meta-Tags for the Document-Scope have to be at the beginning of the file.
The snytax is: `[[gmu.\<option\>=\<value\>]]`
Valid values are:
|Option|Default|Function|Required|
|--|--|--|--|
| defaultWidth | 80 | Width of the seperator | no |
| spacerChar | '#' | Char used for generating the seperators | no |
| indentation | '\\t' | Char/String used to indent the sub-chapters | no |
| title | | Document title | yes |
| shorttitle | | Short title for generating the ASCII-Art | no |
| author | | Document author | yes |
Example:
[[gmu.title=Testdokument]]
[[gmu.shorttitle=Ansible]]
[[gmu.author=Dennis Gunia]]
%% Dies ist ein Kommentar. Einfach ignorieren ....
### Content Tags
Metadata Tags are substituted by the compiler.
The snytax is: `{{gmu.\<option\>(=\<value\>)}}`
Value is only required by section and subsection.
Valid values are:
- header
- contents
- seperator
- section
- subsection
#### header
The **header** generates an ASCII-Art banner with the author and title.
Example:
{{gmu.header}}
Output:
_ _ _ _
/ \ _ __ ___(_) |__ | | ___
/ _ \ | '_ \/ __| | '_ \| |/ _ \
/ ___ \| | | \__ \ | |_) | | __/
/_/ \_\_| |_|___/_|_.__/|_|\___|
Title : Testdokument
Author : Dennis Gunia
The ASCII-Text is defined by `gmu.shorttitle`, the Title is defined by `gmu.title` and the Author is defined by `gmu.author`.
#### contents
The content-tag is replaced with the generated table of contents
Example:
{{gmu.contents}}
Output:
1. Kapitel1
-----------
1.1 Hier gehts weiter
1.2 Hier gehts weiter Pt. 2
2. Kapitel2
-----------
3. Kapitel3
-----------
3.1 Hier gehts weiter Pt. 2
#### seperator
The seperator generates a bar with the symbol specified in `gmu.spacerChar` and a width of `gmu.defaultWidth`.
Example:
{{gmu.seperator}}
Output:
################################################################################
#### section
The section tag generates a new chapter and automatically assigns a chapter number.
Example:
{{gmu.section=Kapitel1}}
Output:
1. Kapitel1
===========
#### subsection
The subsection tag generates a new sub-chapter and automatically assigns a sub-chapter number.
Example:
{{gmu.subsection=Hier gehts weiter}}
Output:
1.1 Hier gehts weiter
---------------------
## Prerequisite
python3.7 -m pip install pyfiglet

Binary file not shown.

229
src/main.py Normal file
View File

@@ -0,0 +1,229 @@
# GuniaMarkup (Primal Markup Language)
import re
import sys
sys.path.append("./")
from render import *
import pyfiglet
import time
import uuid
import sys, getopt
#### VARS
gmuSettings_global = {
'Document' : {
'defaultWidth': 80,
'doctype': 'info',
'spacerChar': '#',
'headerPrefix': 'False',
'indentation': '\t'
},
'counter_section': 0,
'counter_subsection': 0
}
content = []
tmpFileUUID = str(uuid.uuid4())
gmuInputFile = ''
gmuOutputFile = ''
gmuOutputFileTmp = "/tmp/{}.pmc1".format(tmpFileUUID)
currentScope = "Document"
metatagRegEx = re.compile('^\[\[([\w\d._]*)\=([\w\d\-\":;,._$%&\/\\\ ]*)\]\]$', re.IGNORECASE)
contenttagRegEx = re.compile('^\{\{([\w\d._]*)(\=([\w\d\-\":;,._$%&\/\\\ ]*))?\}\}$', re.IGNORECASE)
#### FUNCTIONS
def abortParseError(lineNumber, lineContent, errorMessage):
print ("[ERROR] Parsing error in line {}".format(lineNumber))
print ("> {}".format(lineContent))
print (" ===> {}".format(errorMessage))
exit(1)
def processLine(lineNumber, lineContent, tempFile):
#print("[DEBUG] Line{}: {}".format(lineNumber, lineContent))
if len(lineContent) > 8:
if lineContent[0:6] == "[[gmu.":
# found meta-tag
# pares tag
tagData = metatagRegEx.match(lineContent)
if not tagData:
abortParseError(lineNumber, lineContent, "Cannot parse meta-tag")
gmuSettings_global[currentScope][tagData.group(1)[4:]] = tagData.group(2)
return
if lineContent[0:6] == "{{gmu.":
# found content-tag
tagData = contenttagRegEx.match(lineContent)
if not tagData:
abortParseError(lineNumber, lineContent, "Cannot parse content-tag")
tagType = tagData.group(1)[4:]
if tagType == 'header':
tempFile.write(renderHeader(gmuSettings_global) + '\n')
return
if tagType == 'seperator':
tempFile.write(renderSeperator(gmuSettings_global) + '\n')
return
if tagType == 'section':
gmuSettings_global['counter_section'] += 1
gmuSettings_global['counter_subsection'] = 0
content.append({
'title': tagData.group(3),
'number': gmuSettings_global['counter_section'],
'subsections': []
})
tempFile.write(renderSectionTitle(gmuSettings_global, tagData.group(3)) + '\n')
return
if tagType == 'subsection':
gmuSettings_global['counter_subsection'] += 1
content[gmuSettings_global['counter_section'] - 1]['subsections'].append({
'title': tagData.group(3),
'number': gmuSettings_global['counter_subsection'],
})
tempFile.write(renderSubsectionTitle(gmuSettings_global, tagData.group(3)) + '\n')
return
if tagType == 'contents':
tempFile.write('{{gmu.contents}}\n')
return
if lineContent[0:2] == "%%":
return
tempFile.write(lineContent + '\n')
def processLine2(lineNumber, lineContent, tempFile):
#print("[DEBUG] Line{}: {}".format(lineNumber, lineContent))
if len(lineContent) > 8:
if lineContent[0:6] == "{{gmu.":
# found content-tag
tagData = contenttagRegEx.match(lineContent)
if not tagData:
abortParseError(lineNumber, lineContent, "Cannot parse content-tag")
tagType = tagData.group(1)[4:]
if tagType == 'contents':
tempFile.write(renderContentTable(gmuSettings_global, content ) + '\n')
return
if lineContent[0:2] == "%%":
return
tempFile.write(lineContent + '\n')
def processFile(path):
try:
startTime = time.time()
print("[Phase 1] Processing PrimalMarkupScript-Sourcefile: " + path)
inFile = open(path, 'r')
inFileLines = inFile.readlines()
tempFile = open(gmuOutputFileTmp, 'w')
lineCount = 0
for line in inFileLines:
lineCount += 1
processLine(lineCount, line.strip(), tempFile)
tempFile.close()
endTime = time.time()
print("[Phase 1] Compiled {} lines in {}s".format(lineCount, (endTime - startTime)))
print(" => Registered {} Sections".format(gmuSettings_global['counter_section']))
print(" => Generated pmc1-file {}".format(gmuOutputFileTmp))
except IOError:
print("Sourcefile not accessible")
def processFileRound2(path):
try:
startTime = time.time()
print("[Phase 2] Processing pmc1-file: " + path)
inFile = open(path, 'r')
inFileLines = inFile.readlines()
tempFile = open(gmuOutputFile, 'w')
lineCount = 0
for line in inFileLines:
lineCount += 1
processLine2(lineCount, line[:-1], tempFile)
tempFile.close()
endTime = time.time()
print("[Phase 2] Generated Content-Table in {}s".format((endTime - startTime)))
print(" => Generated info-file {}".format(gmuOutputFile))
except IOError:
print("Sourcefile not accessible")
def printHeader():
print(pyfiglet.figlet_format("PrimalMarkup"))
print("PrimalMarkupScript Compiler v1.0.0")
print("(c)2021 - Dennis Gunia - dennisgunia.de\n")
#### EVALUATE PARAMETERS
full_cmd_arguments = sys.argv
argument_list = full_cmd_arguments[1:]
short_options = "ho:i:"
long_options = ["help", "output=", "input="]
try:
arguments, values = getopt.getopt(argument_list, short_options, long_options)
except getopt.error as err:
print (str(err))
sys.exit(2)
#### MAIN
printHeader()
for current_argument, current_value in arguments:
if current_argument in ("-i", "--input"):
gmuInputFile = current_value
elif current_argument in ("-h", "--help"):
print ("Specify Input with -i or --input")
print ("Specify Output with -o or --output")
exit(0)
elif current_argument in ("-o", "--output"):
gmuOutputFile = current_value
if gmuInputFile == '':
print("[ERROR] You need to specify an input file")
exit(2)
if gmuOutputFile == '':
print("[ERROR] You need to specify an output file")
exit(2)
#check if files exist
processFile(gmuInputFile)
processFileRound2(gmuOutputFileTmp)
print("\nDone! Compiled 1 File.")

51
src/render.py Normal file
View File

@@ -0,0 +1,51 @@
import pyfiglet
def renderSeperator(properties):
outString = ''
for i in range(0, properties['Document']['defaultWidth']):
outString = "{}{}".format(outString, properties['Document']['spacerChar'])
return outString
def renderHeader(properties):
ascii_banner = pyfiglet.figlet_format(properties['Document']['shorttitle'])
ascii_banner = "{}Title : {}".format(ascii_banner,properties['Document']['title'])
ascii_banner = "{}\nAuthor : {}\n".format(ascii_banner,properties['Document']['author'])
return ascii_banner
def repeatChar(symbol, amount):
outString = ''
for i in range(0, int(amount)):
outString = "{}{}".format(outString, symbol)
return outString
def renderSectionTitle(properties, title):
titleString = "{}. {}".format(properties['counter_section'] ,title)
titleLen = len(titleString)
return "{}\n{}".format(titleString, repeatChar('=', titleLen))
def renderSubsectionTitle(properties, title):
titleString = "{}.{} {}".format(properties['counter_section'] ,properties['counter_subsection'] ,title)
titleLen = len(titleString)
return "{}{}\n{}{}".format(properties['Document']['indentation'],titleString, properties['Document']['indentation'], repeatChar('-', titleLen))
def renderContentTable(properties, content):
contentString = ''
for section in content:
sectionNumber = section['number']
titleString = "{}. {}".format(sectionNumber, section['title'])
titleStringLen = len(titleString)
contentString = "{}\n{}\n{}".format(contentString,titleString,repeatChar('-',titleStringLen))
#subsections
for subsection in section['subsections']:
titleString = "{}.{} {}".format(sectionNumber,subsection['number'], subsection['title'])
contentString = "{}\n{}{}".format(contentString,properties['Document']['indentation'],titleString)
contentString = "{}\n".format(contentString)
return contentString[1:]

59
test/test.info Normal file
View File

@@ -0,0 +1,59 @@
################################################################################
_ _ _ _
/ \ _ __ ___(_) |__ | | ___
/ _ \ | '_ \/ __| | '_ \| |/ _ \
/ ___ \| | | \__ \ | |_) | | __/
/_/ \_\_| |_|___/_|_.__/|_|\___|
Title : Testdokument
Author : Dennis Gunia
################################################################################
Inhalt:
=======
1. Kapitel1
-----------
1.1 Hier gehts weiter
1.2 Hier gehts weiter Pt. 2
2. Kapitel2
-----------
3. Kapitel3
-----------
3.1 Hier gehts weiter Pt. 2
################################################################################
1. Kapitel1
===========
Dies ist ein Testdokument
1.1 Hier gehts weiter
---------------------
Wenn der Kühler friert, der Keilriemen durchhängt und Schläuche nicht ganz dicht sind,
kann es dem Motor ganz schön heiß werden. Damit Ihnen Ihr Motor bei Kälte keine Kopfschmerzen bereitet,
sollten Sie Ihr Kühlsystem zum günstigen Komplett-Preis durchchecken lassen.
Ihr Opel-Händler nimmt dabei alle Kühlmittel- und Heizungsschläuche, den Kühler samt ...
1.2 Hier gehts weiter Pt. 2
---------------------------
ur wer seinen Visionen vertraut, kann die Wirklichkeit verändern. Denn Visionen sind es, die uns weiterbringen.
Visionen sind es, die uns und unseren Kunden zu einem wirklichen Wettbewerbsvorsprung verhelfen und neue Perspektiven erschließen.
2. Kapitel2
===========
Dies ist ein Testdokument
3. Kapitel3
===========
Dies ist ein Testdokument
3.1 Hier gehts weiter Pt. 2
---------------------------
wieso?

48
test/test.info.tmp Normal file
View File

@@ -0,0 +1,48 @@
################################################################################
_ _ _ _
/ \ _ __ ___(_) |__ | | ___
/ _ \ | '_ \/ __| | '_ \| |/ _ \
/ ___ \| | | \__ \ | |_) | | __/
/_/ \_\_| |_|___/_|_.__/|_|\___|
Title : Testdokument
Author : Dennis Gunia
################################################################################
Inhalt:
=======
{{gmu.contents}}
################################################################################
1. Kapitel1
===========
Dies ist ein Testdokument
1.1 Hier gehts weiter
---------------------
Wenn der Kühler friert, der Keilriemen durchhängt und Schläuche nicht ganz dicht sind,
kann es dem Motor ganz schön heiß werden. Damit Ihnen Ihr Motor bei Kälte keine Kopfschmerzen bereitet,
sollten Sie Ihr Kühlsystem zum günstigen Komplett-Preis durchchecken lassen.
Ihr Opel-Händler nimmt dabei alle Kühlmittel- und Heizungsschläuche, den Kühler samt ...
1.2 Hier gehts weiter Pt. 2
---------------------------
ur wer seinen Visionen vertraut, kann die Wirklichkeit verändern. Denn Visionen sind es, die uns weiterbringen.
Visionen sind es, die uns und unseren Kunden zu einem wirklichen Wettbewerbsvorsprung verhelfen und neue Perspektiven erschließen.
2. Kapitel2
===========
Dies ist ein Testdokument
3. Kapitel3
===========
Dies ist ein Testdokument
3.1 Hier gehts weiter Pt. 2
---------------------------
wieso?

38
test/test.pms Normal file
View File

@@ -0,0 +1,38 @@
[[gmu.title=Testdokument]]
[[gmu.shorttitle=Ansible]]
[[gmu.author=Dennis Gunia]]
%% Dies it ein Kommentar. Einfach Ignorieren
{{gmu.seperator}}
{{gmu.header}}
{{gmu.seperator}}
Inhalt:
=======
{{gmu.contents}}
{{gmu.seperator}}
{{gmu.section=Kapitel1}}
Dies ist ein Testdokument
{{gmu.subsection=Hier gehts weiter}}
Wenn der Kühler friert, der Keilriemen durchhängt und Schläuche nicht ganz dicht sind,
kann es dem Motor ganz schön heiß werden. Damit Ihnen Ihr Motor bei Kälte keine Kopfschmerzen bereitet,
sollten Sie Ihr Kühlsystem zum günstigen Komplett-Preis durchchecken lassen.
Ihr Opel-Händler nimmt dabei alle Kühlmittel- und Heizungsschläuche, den Kühler samt ...
{{gmu.subsection=Hier gehts weiter Pt. 2}}
ur wer seinen Visionen vertraut, kann die Wirklichkeit verändern. Denn Visionen sind es, die uns weiterbringen.
Visionen sind es, die uns und unseren Kunden zu einem wirklichen Wettbewerbsvorsprung verhelfen und neue Perspektiven erschließen.
{{gmu.section=Kapitel2}}
Dies ist ein Testdokument
{{gmu.section=Kapitel3}}
Dies ist ein Testdokument
{{gmu.subsection=Hier gehts weiter Pt. 2}}
wieso?