Skip to content

Commit

Permalink
Add a workaround to fix leading # in a code block
Browse files Browse the repository at this point in the history
  • Loading branch information
lchen198 committed Jul 22, 2021
1 parent e2d7cff commit 974c8d6
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ Wiki pages are just text files. If you don't want WyPyPlus, you can easily move
**Design Tradeoffs**

* To keep things minimal, WyPyPlus only supports a subset of markdown syntaxes.
* To avoid depending on an external parser, WyPyPlus uses regular expresisons to match tags. It is not perfect, but farily useable.
* To avoid depending on an external parser, WyPyPlus uses regular expresisons to match tags. It is not perfect, but farily useable. Since ^# can be either a headline or a comment in a code block, WyPyPlus inserts a space before # in code block.
* WyPyPlus has no config file. You can't mis-configure it. If you really need something, just edit the source code.

## Install and Use
Expand Down
9 changes: 5 additions & 4 deletions cgi-bin/wypyplus.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
link='\[([^]]*)]\(\s*((?:http[s]?://)?[^)]+)\s*\)';import sys,re,os,cgi;from datetime import timedelta as td;
from datetime import datetime as dt;q,x,h,w=cgi.escape,os.path.exists,'<a href=','wypyplus.py?p='
pre='(?:^|\n)```((?:.|\n)+?)\n```';link='\[([^]]*)]\(\s*((?:http[s]?://)?[^)]+)\s*\)';import sys,re,os,cgi;
from datetime import timedelta as td,datetime as dt
q,x,h,w=cgi.escape,os.path.exists,'<a href=','wypyplus.py?p='
load,t=lambda n:(x('w/'+n) and open('w/'+n).read()) or '','</textarea></form>'
f,i=cgi.FormContent(),'put type';y=f.get('p',[''])[0];y=('WyPyPlus',y)[y.isalpha()]
fs,do,main=lambda s:reduce(lambda s,r:re.sub('(?m)'+r[0],r[1],s),(('\r',''),(\
'(^|[^=/\-_A-Za-z0-9?])(([A-Z][a-z]+){2,})',lambda m:(m.group(1)+'%s'+h+w+m.group(2)+\
'%s>%s</a>')%((m.group(2),'&amp;q=e','?'),('','',m.group(2)))[x('w/'+m.group(2))]),\
('^\{\{$','\n<ul>'),('^\* ','<li>'),('^}}$','</ul>'),('^---$','<hr>'),('```((?:.|\n)+?)```','<pre>\g<1></pre>'),
('^\{\{$','\n<ul>'),('^\* ','<li>'),('^}}$','</ul>'),('^---$','<hr>'),(pre,'<pre>\g<1></pre>'),
('^# (.*)$','<h1>\g<1></h1>'),('^## (.*)$', '<h2>\g<1></h2>'),
('^### (.*)$', '<h3>\g<1></h3>'),('\*\*(.*)\*\*','<b>\g<1></b>'),
('\!'+link,'<img src="\g<2>" alt="\g<1>">'),('(^|[^!])'+link,"\g<1>"+h+'"\g<3>">\g<2></a>'),
('(^|[^"])(http[s]?:[^<>"\s]+)',"\g<1>"+h+'"\g<2>">\g<2></a>'),('\n\n','<p>')),q(s)),\
lambda m,n:{'get':'<h1>%s%sWyPyPlus>WyPyPlus</a>:%s%s%s&amp;q=f>%s</a>:%s%s%s&amp;q=e>✎</a></h1><p>%s'%(\
h,w,h,w,n,n,h,w,n,fs(load(n)) or n),'edit':'<form name="e" action=%s%s method=POST><h1>%s <in'\
h,w,h,w,n,n,h,w,n,fs(re.sub(pre, lambda m: '\n'.join([i if not i.startswith('#') else ' '+i for i in m.group(0).splitlines()]), load(n))) or n),'edit':'<form name="e" action=%s%s method=POST><h1>%s <in'\
'%s=hidden name=p value=%s><in%s=submit></h1>Will auto save at %s<textarea name=t cols=80 rows=24'\
'>%s'%(w,n,fs(n),i,n,i,(dt.now()+td(minutes=30)).strftime("%H:%M"),q(load(n)))+t,'find':('<h1>Links: %s</h1>'%fs(n))+fs(
'{{\n* %s\n}}'%'\n* '.join([d for d in os.listdir('w/') if n == "All" or load(d).count(n)]))
Expand Down
1 change: 1 addition & 0 deletions w/DemoPage
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ Local image:


```
# Python Code
def hello():
print("hello world")
```
Expand Down
93 changes: 66 additions & 27 deletions w/WyPyPlus
Original file line number Diff line number Diff line change
Expand Up @@ -31,50 +31,51 @@ WyPyPlus (pronounced "whippy plus") is a minimalist wiki server in 23 lines of c

## WyPyPlus vs Other Wiki Software

WyPyPlus is the result of a deep meditation to find out the essential of wiki and get rid of everything else. It is the purest form of wiki packed in the tiniest space possible.
WyPyPlus is the result of a deep meditation to find out the essence of personal wiki and get rid of everything else. It tries to keep the purest form of wiki packed in the tiniest space possible.

I tried many solutions in the last decade including MoinMoin wiki, DokuWiki, TiddlyWiki, ZIM, Emacs Org mode and many more. I take work-related notes with Org mode and it works well for me.
WyPyPlus helps you control your personal data by keeping data close to you. It doesn't upload your data to the cloud or a remote server.

I want to keep control of my personal data. Cloud-based services are not ideal for me. Desktop wiki often have display issues when running across multi platforms and various sizes of screens.
Setting up a personal wiki server is not easy. I would set up a Linux and secure it, configure a web front-end, and initialize a database. After that I also need to worry about backing up the data and keeps the system up-to-date. The more features it has, the higher maintenance cost I need to pay. Things add up pretty quickly.
Comparing to other self-hosted Wiki, WyPyPlus is much easier to set up and maintain. You don't need to set up a Linux box and secure it. You don't need to mess with web front-end configurations and database. The more features a software has, the higher maintenance cost you will pay. Things add up pretty quickly. At the end of the day, don't you want a Wiki that just works?

### The key feature of WyPyPluse is the lack of features. (AKA Less is More)
### The key feature of WyPyPluse is the lack of features.

It is just slightly better than a Windows notepad. Wiki pages are just text files. If you don't want WyPyPlus, you can easily move to somewhere else.
Wiki pages are just text files. If you don't want WyPyPlus, you can easily move to somewhere else that supports markdown.

**Benefits**
* Fast!!
* Support just enough wiki syntaxes to be useful. (See [DemoPage](https://github.com/lchen198/wypyplus/blob/main/w/DemoPage))
* Takes less than one minute to set up.
* Takes less than a minute to set up and get going.
* Runs anywhere that has Python and a browser.
* Works perfectly offline.
* No config file to mess with.
* No authentication. It's a personal wiki and you should run it on your own machine.
* No database. Wiki pages are just text files.
* No Javascript.
* Low maintenance. Just backup the entire folder.
* Extendable.

![demo](../example2.png)
**Design Tradeoffs**

## Install and Use

* You need Python 2 to run this application. Mac and Linux already have python 2. For Windows users, please install Python 2.7.
* To keep things minimal, WyPyPlus only supports a subset of markdown syntaxes.
* To avoid depending on an external parser, WyPyPlus uses regular expresisons to match tags. It is not perfect, but farily useable.
* WyPyPlus has no config file. You can't mis-configure it. If you really need something, just edit the source code.

* Download WyPyPlus and extract it to a folder (E.g wypy_wiki). This folder should already contain a cgi-bin directory and a "w" directory. Your file will save into the "w" directory.
## Install and Use

* The following command should work under Mac, Linux and Windows.
* You need Python 2 to run this application. Mac and Linux already have Python 2. For Windows users, please install Python 2.7.

* Download WyPyPlus and extract it to a folder (E.g wypy_wiki).
```
cd wypy_wiki

python -m CGIHTTPServer 8000

Open this url in your browser.
python3 -m http.server --cgi 8000 --bind 127.0.0.1

Open this url in your browser. It takes a few moments to start.
http://127.0.0.1:8000/cgi-bin/wypyplus.py
```

Since the wypyplus file is just a cgi script, you can also use any web server to host it.
Since the wypyplus file is just a cgi script, you can also use any web server to host it. I don't recommend this since you are likely to spend more time to config the cgi server.

The UI should be fairly self-explanatory.
* Click the ? mark after a CamelCased word to create a new page.
Expand All @@ -83,24 +84,62 @@ The UI should be fairly self-explanatory.
### How to create tags
There's no difference between Tags and WikiWords. When you create a new page, there will be a link on the top of the screen to show all pages that reference it.

For example, you can create a page called MyTag, and put the word MyTag to other pages and see references here:
http://127.0.0.1:8000/cgi-bin/wypyplus?p=MyTag&q=f
For example, you can create a page called ToDo, and put the word ToDo to other pages and see references here:
http://127.0.0.1:8000/cgi-bin/wypyplus?p=ToDo&q=f

# Design Tradeoffs

* To keep things minimal, WyPyPlus only supports a subset of markdown syntaxes.
* To avoid depending on an external parser, WyPyPlus uses regular expresisons to match tags. It is not perfect, but farily useable.
* WyPyPlus has no config file. You can't mis-configure it. If you really need something, just edit the source code.
* WyPyPlus doesn't automatically save for you. Don't refresh the page before submitting your change.

# Source Code

The original wypy code is highly compressed. However, variable names are carefully picked so that the code is still somewhat readable. If you read it through, it is not that hard to change.
The original wypy code is highly compressed. However, variable names are carefully picked so that the code is still somewhat readable.

For example, if you don't like the CSS, just replace <head><link rel='stylesheet' href='https://unpkg.com/sakura.css/css/sakura.css' type='text/css'></head> with whatever you like.
For example, if you don't like the CSS, just replace ```<head><link rel='stylesheet' href='..\sakura.css' type='text/css'></head> ```with whatever you like.

To support new syntax, you can add a tuple of (regex_pattern, replace_pattern). The following example extracts content after ## and replace it with <h2>content</h2>.
To support new syntax, you can add a tuple of (regex_pattern, replace_pattern). The following example extracts content after ## and enclose it with an h2 headline.
```
('^## (.*)$', '<h2>\g<1></h2>')
```
Here's the entire source code and my comments.

```
#!/usr/bin/python
# -*- coding: utf-8 -*- Need this line to support the "edit" button unicode.

# Create shorter names for commonly used functions and variables.
link='\[([^]]*)]\(\s*((?:http[s]?://)?[^)]+)\s*\)';import sys,re,os,cgi;from datetime import timedelta as td;
from datetime import datetime as dt;q,x,h,w=cgi.escape,os.path.exists,'<a href=','wypyplus.py?p='
load,t=lambda n:(x('w/'+n) and open('w/'+n).read()) or '','</textarea></form>'
f,i=cgi.FormContent(),'put type';y=f.get('p',[''])[0];y=('WyPyPlus',y)[y.isalpha()]

# Define a list of (regular expressions, replace patterns). Apply them one by one to convert wiki tags.
# Do cgi.escape on the final content.
fs,do,main=lambda s:reduce(lambda s,r:re.sub('(?m)'+r[0],r[1],s),(('\r',''),(\
# Find WikiWords and replace with html links.
'(^|[^=/\-_A-Za-z0-9?])(([A-Z][a-z]+){2,})',lambda m:(m.group(1)+'%s'+h+w+m.group(2)+\
'%s>%s</a>')%((m.group(2),'&amp;q=e','?'),('','',m.group(2)))[x('w/'+m.group(2))]),\
# Other wiki tags sunch as headline and links. Note that a regular expression can match multiple lines.
('^\{\{$','\n<ul>'),('^\* ','<li>'),('^}}$','</ul>'),('^---$','<hr>'),('```((?:.|\n)+?)```','<pre>\g<1></pre>'),
('^# (.*)$','<h1>\g<1></h1>'),('^## (.*)$', '<h2>\g<1></h2>'),
('^### (.*)$', '<h3>\g<1></h3>'),('\*\*(.*)\*\*','<b>\g<1></b>'),
('\!'+link,'<img src="\g<2>" alt="\g<1>">'),('(^|[^!])'+link,"\g<1>"+h+'"\g<3>">\g<2></a>'),
('(^|[^"])(http[s]?:[^<>"\s]+)',"\g<1>"+h+'"\g<2>">\g<2></a>'),('\n\n','<p>')),q(s)),\

# Generate <HomePage>:<CurrentPage>:<Edit Icon>.
lambda m,n:{'get':'<h1>%s%sWyPyPlus>WyPyPlus</a>:%s%s%s&amp;q=f>%s</a>:%s%s%s&amp;q=e>✎</a></h1><p>%s'%(\

# Add a submit button and compute the time for auto save.
h,w,h,w,n,n,h,w,n,fs(load(n)) or n),'edit':'<form name="e" action=%s%s method=POST><h1>%s <in'\
'%s=hidden name=p value=%s><in%s=submit></h1>Will auto save at %s<textarea name=t cols=80 rows=24'\
'>%s'%(w,n,fs(n),i,n,i,(dt.now()+td(minutes=30)).strftime("%H:%M"),q(load(n)))+t,'find':('<h1>Links: %s</h1>'%fs(n))+fs(

# Generate a reverse index of a WikiPage. Note tha the "All" page would match every file in the wiki
'{{\n* %s\n}}'%'\n* '.join([d for d in os.listdir('w/') if n == "All" or load(d).count(n)]))

# This part handles a POST request. If the content is empty, delete the file from disk. Otherwise, write the content to a file under the /w folder.
}.get(m),lambda f=f:`(os.getenv("REQUEST_METHOD")!="POST") or ('t' in f or (os.remove('w/'+y) and False))\
and open('w/'+y,'w').write(f['t'][0])`+`sys.stdout.write("Content-type: text/html; charset=utf-8\r\n\r\n"\

# Insert a CSS link and set a timer to save the content in 30 mins (1.8e6 milliseconds)
"<head><link rel='stylesheet' href='../sakura.css'><script>var wait=setTimeout('document.e.submit();',1.8e6);</script>\
</head><title>%s</title>"%y+do({'e':'edit','f':'find'}.get(f.get('q',[None])[0],'get'),y))`;(__name__=="__main__") and main()
```

0 comments on commit 974c8d6

Please sign in to comment.