diff --git a/README.md b/README.md
index af4b100..50bf72d 100644
--- a/README.md
+++ b/README.md
@@ -2,17 +2,26 @@
Pour obtenir de l'aide, taper juste la commande tyto
## Répertoire de code du projet Tyto
+TODO
## Comment définir les métas
```
# Obligatoires uniques
+# Ces marqueurs se configurent sur UNE ligne
title: Titre
about: Infos de l'article
author: Auteur
-tags: mots-clé-1,mots-clé-2
+tags: mot-clé-1,mot 2,
date: YYYY-MM-DD (AAAA-MM-JJ)
+# L'image doit être configurée avec le même Nom
+# dans les marqueurs multiples
+# Utilise l'image précisée comme "avatar" dans les réseaux sociaux
+snpic: Nom
+
+
# Optionnels multiples
+# Ces marqueurs se configurent sur 3 lignes
link: Nom du lien
URL
Texte Alternatif
@@ -33,10 +42,6 @@ abbr: abbrev
Définition de abbrev
ABBR (forme à afficher dans l'artile (optionnel))
-# L'image doit d'abord être configurée
-# Utiliser l'image précisée comme défaut dans les réseaux sociaux
-snpic: Nom
-
# Séparateur d'au moins 5 "-" pour définir la fin
# des métadonnées d'entête de l'article
----------
@@ -103,13 +108,14 @@ def hello_world():
### Ancres
```
-# Source`
+# Source de l'ancre cible. "id" est son identité
-> id
# HTML
-# Source
+# Source de l'ancre d'appel
+# Définir l'identité cible et le texte du lien
((
>_id:Retourner au point d'ancre id_<
))
@@ -120,7 +126,11 @@ def hello_world():
### Retour à la ligne HTML
```
-| #
+# Source
+|
+
+# HTML
+
```
### Lien vers URL
@@ -136,7 +146,8 @@ Voir ce __Nom du lien+ # ouverture nouvelle fenêtre
```
Note:
-Vous pouvez avoir un Nom identique pour file: et link:
+Vous pouvez avoir un Nom identique pour les marqueur `file:` et `link:`
+
### Gras, Strong, italique...
```
@@ -159,7 +170,7 @@ Vous pouvez avoir un Nom identique pour file: et link:
### Abréviations
```
# abbrev sera remplacé par "ABBR" dans la page si défini en entête
-# sinon, abbrev sera conservé
+# sinon, abbrev sera conservé
# - Toujours écrire dans l'article :
# - entre parenthèses ET majuscules les "(ABBREV)"
@@ -186,12 +197,12 @@ _image:Nom c=CSS t=https://... w=320px h=240 # 240px
### Code brut depuis un fichier
```
-_raw:NOM
+_raw:Nom
```
### Citations
Possibilité dans toute citation d'utiliser les marqueurs
-optionnels _xxx. Pour la date, utilisez le FORMAT INTERNATIONAL
+optionnels `_xxx:`. Pour la date, utilisez le FORMAT INTERNATIONAL
```
# Source: citation complète
[[ CSS_TEST
diff --git a/src/var/lib/tyto/program/args.py b/src/var/lib/tyto/program/args.py
index c7e4732..2c9a86c 100644
--- a/src/var/lib/tyto/program/args.py
+++ b/src/var/lib/tyto/program/args.py
@@ -58,6 +58,7 @@ pass_db = \
'edit-www',
'publish',
'show',
+ 'show-about',
'show-db',
'show-wip',
'show-www',
diff --git a/src/var/lib/tyto/program/check.py b/src/var/lib/tyto/program/check.py
index 556413a..5e02a6d 100644
--- a/src/var/lib/tyto/program/check.py
+++ b/src/var/lib/tyto/program/check.py
@@ -1,11 +1,28 @@
#!/usr/bin/env python3
-# Name: Tyto - Littérateur
-# Type: Global functions for check
-# Description: Check article contents. Create Stats and Database
-# file: check.py
-# Folder: /var/lib/tyto/program/
-# By echolib (XMPP: im@echolib.re)
-# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
+# Tyto - Littérateur
+#
+# Copyright (C) 2023 Cyrille Louarn
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License
+# as published by the Free Software Foundation, either version 3 of the License, or
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+#----------------------------------------------------------------------
+# XMPP: echolib (im@echolib.re)
+#
+# Description: Manage 'check' argument.
+# Check article's validity in Tyto's format
+# File: /var/lib/tyto/program/check.py
+#----------------------------------------------------------------------
#------------
# funny stats
@@ -115,7 +132,7 @@ def check_all(option):
if option == 'all' and not db.old_chk: continue
found = True
- print(':> [%s] - %s'%(db.title, db.post_src))
+ print(' ├ [%s] > %s'%(db.title, db.post_src))
check_process(args.target)
if post_err: logs.out("44", args.target, False)
@@ -279,24 +296,19 @@ def count_words(post_bottom):
#---------------------------------------------#
def if_icodes_bcodes_quotes(post_bottom):
global icode, quote, bcode, post_err
- global nbr_titles, nbr_quotes, nbr_bcodes, nbr_ancs
+ global nbr_titles, nbr_quotes, nbr_bcodes, nbr_ancs, nbr_coms
- icode = quote = in_quote = bcode = in_bcode = False
- nbr_titles = nbr_quotes = nbr_bcodes = nbr_ancs = 0
+ icode = quote = in_quote = bcode = in_bcode = in_bq = False
+ nbr_titles = nbr_quotes = nbr_bcodes = nbr_ancs = nbr_coms = 0
- for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
- # Comments, count titles
+ for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
+ # Stat Comments, Titles, Anchors
if not line:
continue
- elif line.startswith(tyto.titles_tags):
- nbr_titles += 1
- continue
- elif line.startswith('#'):
- continue
# quotes
elif line.startswith(tyto.words_tags[11][0]) and not in_bcode:
- quote = in_quote = True
+ quote = in_quote = in_bq = True
continue
elif line.startswith(tyto.words_tags[11][1]):
in_quote = False
@@ -305,18 +317,25 @@ def if_icodes_bcodes_quotes(post_bottom):
# bcode
elif line.startswith(tyto.words_tags[12][0]) and not in_quote:
- bcode = in_bcode = True
+ bcode = in_bcode = in_bq = True
continue
elif line.startswith(tyto.words_tags[12][1]):
in_bcode = False
nbr_bcodes += 1
continue
- if in_bcode or in_quote:
+ if in_bq:
continue
- elif line.startswith(tyto.single_tags[1][0]):
+ elif line.startswith(tyto.titles_tags) and not in_bq:
+ nbr_titles += 1
+ continue
+ elif line.startswith('#') and not in_bq:
+ nbr_coms += 1
+ continue
+ elif line.startswith(tyto.single_tags[1][0]) and not in_bq:
nbr_ancs += 1
+ continue
# icodes
elif tyto.words_tags[9][0] or tyto.words_tags[9][1] in line:
@@ -409,14 +428,14 @@ def check_date(date):
# Multiple settings for each on 3 lines #
#-------------------------------------------#
def check_opt_tags(post_header):
- global stat_links, stat_images, stat_files, stat_raws, stat_abbrs
- global stat_snpics, snpic_url
+ global stat_links, stat_images, stat_files, stat_raws
+ global stat_snpics, snpic_url, stat_abbrs, post_abbrs
global opt_tags_post_name
global files_post
# Statistics
- stat_links = stat_images = stat_files = stat_raws = stat_abbrs = 0
- stat_snpics = 0
+ stat_links = stat_images = stat_files = stat_raws = 0
+ stat_snpics = post_abbrs = stat_abbrs = 0
files_post = (())
# Set default post pic
@@ -446,8 +465,9 @@ def check_opt_tags(post_header):
#--------------------------------------------#
def check_3lines(tag, ln, line):
global post_err, db_tag, files_post
+ global post_abbrs
- stat_tag = "stat_%ss"%tag
+ stat_tag = "stat_%ss"%tag
# Create variable for post DB
globals()[stat_tag] += 1
@@ -462,8 +482,7 @@ def check_3lines(tag, ln, line):
name = line.rsplit('%s:'%tag)[1].lstrip()
else:
name = line.rsplit('%s:'%tag)[1].lstrip().rsplit(' ')[0]
- if tag == "abbr":
- name = name.upper()
+
if not name:
logs.out("2", 'L=%s. "%s: %s" > %s'%(
@@ -471,6 +490,11 @@ def check_3lines(tag, ln, line):
), False)
post_err = True
+ # abbr:
+ elif tag == "abbr":
+ name_abbr = name.upper()
+ post_abbrs = post_bottom.count('(%s)'%name_abbr)
+
# snpic only needs a Name
elif tag == "snpic":
check_snpic(name)
@@ -482,7 +506,7 @@ def check_3lines(tag, ln, line):
), False)
post_err = True
- globals()[db_tag] = ((name),)
+ globals()[db_tag] = ((opt_tags_post_name[tag]%name),)
# URI/URL and Alt-Text
#---------------------
@@ -509,9 +533,13 @@ def check_3lines(tag, ln, line):
# Set data for post DB
if l == 1 and tag in tyto.opt_tags_check_uri:
check_file_uri(tag, data, ln)
+ if post_err:
+ return
globals()[db_tag] = globals()[db_tag] + ((web_uri),)
files_post = files_post + (('%s'%web_uri),)
else:
+ if post_err:
+ return
globals()[db_tag] = globals()[db_tag] + ((data),)
@@ -603,78 +631,6 @@ def check_snpic(name):
def check_content(post_bottom):
global post_err
- # Check if anchor has target
- # Count anchors target
- #---------------------------
- for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
- # Anchor link
- if tyto.words_tags[0][0] and tyto.words_tags[0][1] in line:
- anchors = re.findall(r">_(.*?)_<", line)
- for anchor in anchors:
- css_anchor = anchor.rsplit(':')[0]
- tag = '%s %s'%(tyto.single_tags[1][0], css_anchor)
- if not tag in post_bottom:
- logs.out("12", 'L=%s. anchor "%s" > %s'%(
- ln + ln_header, tag, db.uri_file
- ), False)
- post_err = True
-
- # Anchor source "->"
- if line.startswith(tyto.single_tags[1][0]):
- set_css = tyto.get_css(line)
- is_uniq_anchor = "%s %s"%(tyto.single_tags[1][0], set_css)
- c_uniq_anchor = post_bottom.count(is_uniq_anchor)
- if c_uniq_anchor > 1:
- logs.out("15", 'L=%s. %sx "%s" > %s'%(
- ln + ln_header, c_uniq_anchor, is_uniq_anchor,
- db.uri_file
- ), False)
- post_err = True
- break
-
-
- # Lists: check if contents are valid
- #-----------------------------------
- inlist = False
- markers_lists = '%s, %s, or space'%(
- tyto.markers_lists[0],
- tyto.markers_lists[1]
- )
- for ln, line in enumerate(article.rsplit('\n'), 1):
- if line.startswith('-('): inlist = True;continue
- elif line.startswith('-)'): inlist = False
- if not inlist: continue
-
- if inlist and not line or not line[0] in tyto.markers_lists:
- logs.out("3", 'line %s must start with %s'%(
- ln, markers_lists
- ), False
- )
- post_err = True
-
-
- # Check for all match _TAGS:NAME from content in header
- #------------------------------------------------------
- set_tags = ()
- for ln, line in enumerate(post_bottom):
- for htag in tyto.head_tags:
- match = False
- ptag = '_%s'%htag
-
- if line.startswith(ptag):
- ptag_set = line.rsplit(':', 1)[1].lstrip().rsplit(' ')[0]
- if ptag_set in set_tags: continue
- for hline in post_header:
- if re.search(r"^%s\s+%s$"%(htag,ptag_set), hline):
- match = True
- set_tags = (ptag_set)
-
- if match: continue
- else:
- logs.out("12", "%s %s"%(htag, ptag_set), False)
- post_err = True
-
-
# Check tags for words (strongs, italics...)
# Set stats for each one
#-------------------------------------------
@@ -702,6 +658,85 @@ def check_content(post_bottom):
globals()['post_%s'%tag[4]] = int(c_opened)
+ # Check if anchor has target
+ # Count anchors target
+ #---------------------------
+ if post_anchors > 0:
+ for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
+ # Anchor link
+ if tyto.words_tags[0][0] and tyto.words_tags[0][1] in line:
+ anchors = re.findall(r">_(.*?)_<", line)
+ for anchor in anchors:
+ css_anchor = anchor.rsplit(':')[0]
+ tag = '%s %s'%(tyto.single_tags[1][0], css_anchor)
+ if not tag in post_bottom:
+ logs.out("12", 'L=%s. anchor "%s" > %s'%(
+ ln + ln_header, tag, db.uri_file
+ ), False)
+ post_err = True
+
+ # Anchor "->" id must be uniq
+ if nbr_ancs > 0:
+ if line.startswith(tyto.single_tags[1][0]):
+ set_css = tyto.get_css(line)
+ is_uniq_anchor = "%s %s"%(tyto.single_tags[1][0], set_css)
+ c_uniq_anchor = post_bottom.count(is_uniq_anchor)
+ if c_uniq_anchor > 1:
+ logs.out("15", 'L=%s. %sx "%s" > %s'%(
+ ln + ln_header, c_uniq_anchor, is_uniq_anchor,
+ db.uri_file
+ ), False)
+ post_err = True
+ break
+
+
+ # Lists: check if contents are valid
+ #-----------------------------------
+ if post_lists > 0:
+ inlist = False
+ for ln, line in enumerate(post_bottom.rsplit('\n'), 1):
+ if line.startswith(tyto.words_tags[13][0]):
+ inlist = True
+ continue
+ elif line.startswith(tyto.words_tags[13][1]):
+ inlist = False
+
+ if not inlist:
+ continue
+
+ if inlist and not line or not line[0] in tyto.markers_lists:
+ logs.out("3", 'L=%s. %s %s > %s'%(
+ ln + ln_header,
+ tyto.words_tags[13][4],
+ tyto.markers_lists,
+ db.uri_file
+ ), False
+ )
+ post_err = True
+
+
+ # Check for all match _TAGS:NAME from content in header
+ #------------------------------------------------------
+ set_tags = ()
+ for ln, line in enumerate(post_bottom):
+ for htag in tyto.head_tags:
+ match = False
+ ptag = '_%s'%htag
+
+ if line.startswith(ptag):
+ ptag_set = line.rsplit(':', 1)[1].lstrip().rsplit(' ')[0]
+ if ptag_set in set_tags: continue
+ for hline in post_header:
+ if re.search(r"^%s\s+%s$"%(htag, ptag_set), hline):
+ match = True
+ set_tags = (ptag_set)
+
+ if match: continue
+ else:
+ logs.out("12", "%s %s"%(htag, ptag_set), False)
+ post_err = True
+
+
# Template Tags (warning for not paired symbols)
#-----------------------------------------------
for tag in tyto.tpl_tags:
@@ -803,24 +838,26 @@ def create_database():
'uniq_files = %d\n'%stat_files + \
'uniq_raws = %d\n'%stat_raws + \
'\n# Statistics from post content\n' + \
- 'stat_tags = %d\n'%stat_tags + \
- 'stat_lines = %d\n'%ln_article + \
- 'stat_words = %d\n'%stat_words + \
- 'stat_titles = %d\n'%nbr_titles + \
- 'stat_paragraphs = %d\n'%post_paragraphs + \
- 'stat_anchors = %d\n'%post_anchors + \
- 'stat_strongs = %d\n'%post_strongs + \
- 'stat_bolds = %d\n'%post_bolds + \
- 'stat_emphasis = %d\n'%post_emphasis + \
- 'stat_italics = %d\n'%post_italics + \
- 'stat_dels = %d\n'%post_dels + \
- 'stat_underlines = %d\n'%post_underlines + \
- 'stat_cites = %d\n'%post_cites + \
- 'stat_customs = %d\n'%post_customs + \
- 'stat_icodes = %d\n'%tyto.nbr_icodes + \
- 'stat_bcodes = %d\n'%nbr_bcodes + \
- 'stat_quotes = %d\n'%nbr_quotes + \
- 'stat_lists = %d\n'%post_lists
+ 'post_coms = %d\n'%nbr_coms + \
+ 'post_tags = %d\n'%stat_tags + \
+ 'post_lines = %d\n'%ln_article + \
+ 'post_words = %d\n'%stat_words + \
+ 'post_titles = %d\n'%nbr_titles + \
+ 'post_paragraphs = %d\n'%post_paragraphs + \
+ 'post_anchors = %d\n'%post_anchors + \
+ 'post_abbrs = %d\n'%post_abbrs + \
+ 'post_strongs = %d\n'%post_strongs + \
+ 'post_bolds = %d\n'%post_bolds + \
+ 'post_emphasis = %d\n'%post_emphasis + \
+ 'post_italics = %d\n'%post_italics + \
+ 'post_dels = %d\n'%post_dels + \
+ 'post_underlines = %d\n'%post_underlines + \
+ 'post_cites = %d\n'%post_cites + \
+ 'post_customs = %d\n'%post_customs + \
+ 'post_icodes = %d\n'%tyto.nbr_icodes + \
+ 'post_bcodes = %d\n'%nbr_bcodes + \
+ 'post_quotes = %d\n'%nbr_quotes + \
+ 'post_lists = %d\n'%post_lists
# Create Post DB
#---------------
@@ -828,336 +865,3 @@ def create_database():
tyto.set_file(db.config, 'new', database)
logs.out("21", db.uri_file, False)
-
-
-
-
-
-
-#==================================#
-# Check tags from article's header #
-#----------------------------------#
-def check_headers(post_header):
- global post_err, err, web_uri, date_check
- global date, title, author, tags, about
- global stat_links, stat_images, stat_files, stat_raws, stat_abbrs
- global post_tags
- global snpic_url
- global files_post
-
- # Contains all files URIs needed for article
- # Used with publish command to copy needed files
- files_post = ('')
-
- snshare = False
- snpic_name = ''
-
- # Needed Tags
- title = author = about = tags = ''
- date = ()
-
- # Statistics
- stat_links = stat_images = stat_files = stat_raws = stat_abbrs = 0
-
-
-###
- # Second session for optional tags #
- # Read articles lines, till separator #
- #-------------------------------------#
- for ln, line in enumerate(post_header, 1):
- if line.startswith('-----'): break
-
- # Set each optional tags
- #-----------------------
- # ABBR
- #-----
- tag = tyto.headers[8] # abbr:
- if line.startswith(tag):
- stat_abbrs += 1
- var_tag = 'abbr_%s'%stat_abbrs
-
- abbr_short = post_header[ln - 1].rsplit(tag)[1].lstrip()
- if not abbr_short:
- logs.out("2", "Line %s (SHORT, %s)"%(ln, tag), False)
- post_err = True
- if not abbr_short.isupper():
- logs.out("3", "Line %s (Upper SHORT, %s)"%(ln, tag), False)
- post_err = True
- continue
- if not isin(r'!\b%s\b'%abbr_short, post_bottom):
- logs.out("6", '!%s'%abbr_short, False)
- post_err = True
-
- abbr_long = post_header[ln].lstrip()
- if abbr_long.startswith(tyto.headers): abbr_long = ''
- if not abbr_long:
- logs.out("2", "Line %s (Long, %s)"%(ln + 1, tag), False)
- post_err = True
-
- abbr_alt = post_header[ln + 1].lstrip()
- if abbr_alt.startswith(tyto.headers): abbr_alt = ''
- if not abbr_alt: abbr_alt = abbr_short
-
- if not post_err:
- web_link = '%s'%(
- 'abbr', abbr_long, abbr_alt
- )
- globals()['abbr_%s'%stat_abbrs] = (
- '!%s'%abbr_short, web_link
- )
-
- # LINK
- #-----
- tag = tyto.headers[5] # link:
- if line.startswith(tag):
- stat_links += 1
- var_tag = 'link_%s'%stat_links
-
- # NAME
- link_name = post_header[ln - 1].rsplit(tag)[1].lstrip()
- if not link_name:
- logs.out("2", 'L=%s. "%s %s" > %s'%(
- ln, tag, tr.name, db.uri_file
- ), False)
- post_err = True
- if not post_err and \
- not isin(r'\b_%s\b'%link_name, post_bottom):
- logs.out("12", '"_%s%s" > %s'%(
- tag, image_name, db.uri_file
- ), False)
- post_err = True
-
- # URL
- try:
- link_url = post_header[ln].lstrip()
- if link_url.startswith(tyto.headers): link_url = ''
- except:
- link_url = ''
-
- if not link_url:
- logs.out("2", 'L=%s. "%s URL" > %s)'%(
- ln + 1, tag, db.uri_file
- ), False)
- post_err = True
-
- # ALT
- try:
- link_alt = post_header[ln + 1].lstrip()
- if link_alt.startswith(tyto.headers): link_alt = ''
- except:
- link_alt = ''
-
- if not link_alt:
- logs.out("2", 'L=%s. "%s Alt-Text" > %s'%(
- ln + 2, tag, db.uri_file
- ), False)
- post_err = True
-
- if not post_err:
- web_link = '%s'%(
- '%s', link_alt, link_name
- )
- globals()['link_%s'%stat_links] = (
- '_%s'%link_name, web_link
- )
-
- # IMAGE
- #------
- tag = tyto.headers[6] # image:
- if line.startswith(tag):
- stat_images += 1
- var_tag = 'image_%s'%stat_images
-
- # NAME
- image_name = post_header[ln - 1]
- image_name = image_name.rsplit(tag)[1].lstrip().rsplit(' ')[0]
- if not image_name:
- logs.out("2", 'L=%s. "%s %s" > %s'%(
- ln, tag, tr.name, db.uri_file
- ), False)
- post_err = True
- if not post_err and \
- not isin(r'\b_%s%s\b'%(tag, image_name), post_bottom):
- logs.out("12", '"_%s%s" > %s'%(
- tag, image_name, db.uri_file
- ), False)
- post_err = True
-
- # URI
- try:
- image_uri = post_header[ln].lstrip()
- if image_uri.startswith(tyto.headers): image_uri = ''
- except:
- image_uri = ''
-
- if not image_uri:
- logs.out("2", 'L=%s. "%s URI" > %s)'%(
- ln + 1, tag, db.uri_file
- ), False)
- post_err = True
- else:
- check_file_uri('image', image_uri, ln + 1)
- if not post_err:
- f_uri = web_uri[1:len(web_uri)]
- files_post = (files_post + "'%s', "%f_uri)
-
- # ALT
- try:
- image_alt = post_header[ln + 1].lstrip()
- if image_alt.startswith(tyto.headers): image_alt = ''
- except:
- image_alt = ''
-
- if not image_alt:
- logs.out("2", 'L=%s. "%s Alt-Text" > %s'%(
- ln + 2, tag, db.uri_file
- ), False)
- post_err = True
-
- if not post_err:
- globals()['image_%s'%stat_images] = (
- '_%s%s'%(tag, image_name),
- web_uri,
- image_alt
- )
-
- # RAW File
- #---------
- tag = tyto.headers[9] # raw:
- if line.startswith(tag):
- stat_raws += 1
- var_tag = 'raw_%s'%stat_raws
-
- # NAME
- raw_name = post_header[ln - 1]
- raw_name = raw_name.rsplit(tag)[1].lstrip().rsplit(' ')[0]
- if not raw_name:
- logs.out("2", 'L=%s. "%s %s" > %s'%(
- ln, tag, tr.name, db.uri_file
- ), False)
- post_err = True
- if not post_err and \
- not isin(r'\b_%s%s\b'%(tag, raw_name), post_bottom):
- logs.out("12", '"_%s%s" > %s'%(
- tag, raw_name, db.uri_file
- ), False)
- post_err = True
-
- # URI
- try:
- raw_uri = post_header[ln].lstrip()
- if raw_uri.startswith(tyto.headers): raw_uri = ''
- except:
- raw_uri = ''
-
- if not raw_uri:
- logs.out("2", 'L=%s. "%s URI" > %s)'%(
- ln + 1, tag, db.uri_file
- ), False)
- post_err = True
- else:
- check_file_uri('file', raw_uri, ln + 1)
- if not post_err:
- f_uri = web_uri[1:len(web_uri)]
- files_post = (files_post + "'%s', "%f_uri)
-
- # ALT
- try:
- raw_alt = post_header[ln + 1].lstrip()
- if raw_alt.startswith(tyto.headers): raw_alt = ''
- except:
- raw_alt = ''
-
- if not raw_alt:
- logs.out("2", 'L=%s. "%s Alt-Text" > %s'%(
- ln + 2, tag, db.uri_file
- ), False)
- post_err = True
-
- if not post_err:
- globals()['raw_%s'%stat_raws] = (
- '_%s%s'%(tag, raw_name),
- web_uri,
- raw_alt
- )
-
- # FILE
- #-----
- tag = 'file:'
- if line.startswith(tag):
- stat_files += 1
- var_tag = 'file_%s'%stat_files
-
- # NAME
- file_name = post_header[ln - 1].rsplit(tag)[1].lstrip()
- if not file_name:
- logs.out("2", "Line %s (Name, %s)"%(ln, tag), False)
- post_err = True
- if not post_err and \
- not isin(r'\b__%s\b'%file_name, post_bottom):
- logs.out("6", "__%s"%file_name, False)
- post_err = True
-
- # URI
- try:
- file_uri = post_header[ln].lstrip()
- if file_uri.startswith(tyto.headers): file_uri = ''
- except:
- file_uri = ''
-
- if not file_uri:
- logs.out("2", 'L=%s. "%s URI" > %s)'%(
- ln + 1, tag, db.uri_file
- ), False)
- post_err = True
- else:
- check_file_uri('file', file_uri, ln + 1)
- if not post_err:
- f_uri = web_uri[1:len(web_uri)]
- files_post = (files_post + "'%s', "%f_uri)
-
- # ALT
- try:
- file_alt = post_header[ln + 1].lstrip()
- if file_alt.startswith(tyto.headers): file_alt = ''
- except:
- file_alt = ''
-
- if not file_alt:
- logs.out("2", 'L=%s. "%s Alt-Text" > %s'%(
- ln + 2, tag, db.uri_file
- ), False)
- post_err = True
-
- if not post_err:
- web_link = '%s'%(
- '%s', file_alt, file_name
- )
- globals()['file_%s'%stat_files] = (
- '__%s'%file_name, web_link
- )
-
- # snpic (set image to share to social networks)
- #----------------------------------------------
- if snpic_name: continue
-
- snpic_url = '%s/template/%s'%(dom.www_url, dom.logo)
- tag = tyto.headers[11] # snpic:
- if line.startswith(tag):
- snpic_name = post_header[ln - 1].rsplit(tag)[1].lstrip()
-
- for ln, line in enumerate(post_header, 1):
- if re.search(r"^image:\s+%s$"%snpic_name, line):
- image_uri = post_header[ln].lstrip()
- check_file_uri('image', image_uri, ln + 1)
- snshare = True
- snpic_url = '%s%s'%(dom.www_url, web_uri)
- break
-
- if not snshare:
- logs.out("12", '%s %s'%(tyto.headers[6], snpic_name), False)
- post_err = True
-
-
diff --git a/src/var/lib/tyto/program/db.py b/src/var/lib/tyto/program/db.py
index 2408988..df750ac 100644
--- a/src/var/lib/tyto/program/db.py
+++ b/src/var/lib/tyto/program/db.py
@@ -89,23 +89,25 @@ if args.target \
'uniq_images',
'uniq_files',
'uniq_raws',
- 'stat_tags',
- 'stat_words',
- 'stat_titles',
- 'stat_paragraphs',
- 'stat_anchors',
- 'stat_strongs',
- 'stat_bolds',
- 'stat_emphasis',
- 'stat_italics',
- 'stat_dels',
- 'stat_underlines',
- 'stat_cites',
- 'stat_customs',
- 'stat_icodes',
- 'stat_bcodes',
- 'stat_quotes',
- 'stat_lists'
+ 'post_coms',
+ 'post_tags',
+ 'post_words',
+ 'post_titles',
+ 'post_paragraphs',
+ 'post_anchors',
+ 'post_abbrs',
+ 'post_strongs',
+ 'post_bolds',
+ 'post_emphasis',
+ 'post_italics',
+ 'post_dels',
+ 'post_underlines',
+ 'post_cites',
+ 'post_customs',
+ 'post_icodes',
+ 'post_bcodes',
+ 'post_quotes',
+ 'post_lists'
)
for value in values:
diff --git a/src/var/lib/tyto/program/form.py b/src/var/lib/tyto/program/form.py
index 94aa507..501a85f 100644
--- a/src/var/lib/tyto/program/form.py
+++ b/src/var/lib/tyto/program/form.py
@@ -659,7 +659,7 @@ def create_domain(target):
except: active = False
print(tr.form_warn)
- show.read_lines(dom.config)
+ show.read_lines(dom.config, False)
# Activate and prepare domain ?
#------------------------------
@@ -677,12 +677,10 @@ def create_domain(target):
#----------------
tyto.set_file(dom.config, False, '\nactivated = True')
-
# RELoad config
#--------------
importlib.reload(dom)
-
# Create folders from configuration file
#---------------------------------------
folders = \
diff --git a/src/var/lib/tyto/program/html.py b/src/var/lib/tyto/program/html.py
index f126492..369199d 100644
--- a/src/var/lib/tyto/program/html.py
+++ b/src/var/lib/tyto/program/html.py
@@ -1,11 +1,26 @@
-#!/usr/bin/env python3
-# Name: Tyto - Littérateur
-# Type: HTML template
-# Description: Create raw HTML template
-# file: html.py
-# Folder: /var/lib/tyto/program/
-# By echolib (XMPP: im@echolib.re)
-# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
+# Tyto - Littérateur
+#
+# Copyright (C) 2023 Cyrille Louarn
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License
+# as published by the Free Software Foundation, either version 3 of the License, or
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+#----------------------------------------------------------------------
+# XMPP: echolib (im@echolib.re)
+#
+# Description: Create HTML page
+# File: /var/lib/tyto/program/show.py
+#----------------------------------------------------------------------
#------------
# funny stats
@@ -19,7 +34,7 @@
import os, sys, importlib
-import logs, dom, tyto, form
+import logs, db, dom, tyto, form
# load locale translation
trans_dir = '/var/lib/tyto/translations'
@@ -64,22 +79,22 @@ def create_metas_page():
#-------------------
metas_page = ''
scale = 'width=device-width, initial-scale=1.0'
- all_tags = db.domain_tags + ',' + db.tags
+ all_tags = dom.tags + ',' + db.tags
css_file = 'styles.css'
css_ref = 'href="%stemplate/%s"'%(db.sub_uri, css_file)
rss_ref = 'type="application/rss+xml" ' + \
'href="%s%s" title="RSS 2.0. %s %s %s"'%(
- db.sub_uri, db.domain_rss,
- db.domain_title, db.domain_sep, db.domain_short
+ db.sub_uri, dom.rss,
+ dom.title, dom.sep, dom.shortname
)
icon_file = 'favicon.png'
icon_ref = 'type="image/png" href="%stemplate/%s"'%(
db.sub_uri, icon_file
)
relme = '' # External URL in metas (if exists in config domain)
- if db.domain_relme:
+ if dom.relme:
relme = '\n '%(
- db.domain_relme
+ dom.relme
)
# Create author and date publish section infos
@@ -91,10 +106,10 @@ def create_metas_page():
metas = \
'\n' + \
' \n'%scale + \
- ' \n'%db.domain_www_url + \
- ' \n'%db.domain_lang + \
- ' \n'%db.domain_mail + \
- ' \n'%db.domain_license + \
+ ' \n'%dom.www_url + \
+ ' \n'%dom.lang_site + \
+ ' \n'%dom.mail + \
+ ' \n'%dom.license + \
' \n'%tyto.Tyto + \
' \n'%db.title + \
' \n'%db.author + \
@@ -106,14 +121,14 @@ def create_metas_page():
' \n'%css_ref + \
' \n'%icon_ref + \
' \n' + \
- ' \n'%db.domain_title + \
+ ' \n'%dom.title + \
' \n'%db.title + \
' \n' + \
' \n'%db.http_www + \
' \n'%db.about + \
' \n'%db.snpic + \
'%s'%relme + \
- ' %s'%db.title
+ ' %s %s %s'%(db.title, dom.sep, dom.title)
#=======================================#
@@ -122,23 +137,23 @@ def create_metas_page():
def create_main_page(target, article_bottom):
global main_page
- if not tyto.exists(db.wip_footer):
- logs.out("1", db.wip_footer, True)
+ if not tyto.exists(dom.wip_footer_f):
+ logs.out("1", dom.wip_footer_f, True)
- if not tyto.exists(db.wip_metas):
- logs.out("24", '(HTML metas): %s'%db.wip_metas, False)
+ if not tyto.exists(dom.wip_metas_f):
+ logs.out("24", '(HTML metas): %s'%dom.wip_metas_f, False)
# Create link for website's logo
#-------------------------------
logo_html = '\n'%(11 * " ") + \
'%s\n'%(15 * " ") + \
'%s'%(8 * " ")
@@ -147,7 +162,7 @@ def create_main_page(target, article_bottom):
#-----------------------#
main_page = \
'\n' + \
- '\n'%db.domain_lang + \
+ '\n'%dom.lang_site + \
' \n' + \
'%s\n'%metas + \
' \n\n' + \
@@ -161,9 +176,9 @@ def create_main_page(target, article_bottom):
' \n' + \
- ' %s
\n'%db.domain_title + \
+ ' %s
\n'%dom.title + \
' \n' + \
- ' %s
\n'%db.domain_about + \
+ ' %s
\n'%dom.about + \
' \n' + \
'\n' + \
' \n' + \
@@ -187,7 +202,7 @@ def create_main_page(target, article_bottom):
#--------------------------------------------#
def create_html_infos_section(process):
# Need to reload the DB to get last time updated
- exec(open(db.post_db).read(), globals())
+ exec(open(db.config).read(), globals())
global post_pub, meta_pub, date_raw
if process == 'wip':
@@ -205,7 +220,7 @@ def create_html_infos_section(process):
# Show source code in article-infos if True in DB
post_code = ''
- if db.article_code:
+ if dom.article_code:
# Set HTML
post_code = \
' ' + \
@@ -213,7 +228,7 @@ def create_html_infos_section(process):
os.path.basename(db.short_src),
tyto.trans[21][tyto.n],
tyto.trans[3][tyto.n]
- )
+ ) + \
' '
@@ -248,26 +263,24 @@ def create_html_infos_section(process):
# Create HTML sidebar from file tyto.sidebar #
#--------------------------------------------#
def create_sidebar(option):
- domain.domain_needed
+ dom.valid()
try:
- db.sidebar_load
- if not tyto.exists(db.sidebar_load):
- logs.out("1", db.sidebar_load, True)
+ if not tyto.exists(dom.sidebar_f):
+ logs.out("1", dom.sidebar_f, True)
except:
- logs.out("1", 'Sidebar load file', True)
+ logs.out("1", 'Sidebar ?', True)
try:
- db.sidebar_items
- if int(db.sidebar_items) > 16: db.sidebar_items = 6
+ if int(dom.sidebar_items) > 16: db.sidebar_items = 6
except:
db.sidebar_items = 6
pub_opts = ('www', 'pub')
- if option == 'wip': target = db.wip_sidebar
- elif option == 'www': target = db.www_sidebar
- elif option == 'pub': target = db.www_sidebar
+ if option == 'wip': target = dom.wip_sidebar_f
+ elif option == 'www': target = dom.www_sidebar_f
+ elif option == 'pub': target = dom.www_sidebar_f
# If content in sidebar, go True
sidebar_new = False
@@ -285,8 +298,8 @@ def create_sidebar(option):
counter = 0
nolines = ('#', '/')
- sidebar_title = db.sidebar_title
- sidebar_lines = open(db.sidebar_load, 'r').read()
+ sidebar_title = dom.sidebar_title
+ sidebar_lines = open(dom.sidebar_f, 'r').read()
for line in sidebar_lines.rsplit('\n'):
if not line or line.startswith(nolines): continue
@@ -296,14 +309,14 @@ def create_sidebar(option):
# Get full article URI and check if exists
sidebar_has = True
- f_uri = '%s%s'%(db.domain_articles, line)
+ f_uri = '%s%s'%(dom.articles_d, line)
if not tyto.exists(f_uri):
logs.out("24", f_uri, False)
continue
# Get Hash from uri to get db file
hash_uri = tyto.get_filesum(f_uri, False)
- db_uri = '%s%s.conf'%(db.articles_db, hash_uri)
+ db_uri = '%s%s.config'%(dom.articles_db_d, hash_uri)
if not tyto.exists(db_uri):
logs.out('25', line, False)
continue
@@ -332,9 +345,9 @@ def create_sidebar(option):
# Count: no more than max configured items
counter += 1
- if counter > db.sidebar_items:
+ if counter > dom.sidebar_items:
logs.out("31", '(%s): %s "%s"'%(
- db.sidebar_items, line, title),
+ dom.sidebar_items, line, title),
False
)
continue
diff --git a/src/var/lib/tyto/program/show.py b/src/var/lib/tyto/program/show.py
index 3d571a8..b8febea 100644
--- a/src/var/lib/tyto/program/show.py
+++ b/src/var/lib/tyto/program/show.py
@@ -1,11 +1,28 @@
#!/usr/bin/env python3
-# Name: Tyto - Littérateur
-# Type: Command arguments 'show', 'showdb' manager
-# Description: manage 'show' and 'showdb' from command action argument
-# file: show.py
-# Folder: /var/lib/tyto/program/
-# By echolib (XMPP: im@echolib.re)
-# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
+# Tyto - Littérateur
+#
+# Copyright (C) 2023 Cyrille Louarn
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License
+# as published by the Free Software Foundation, either version 3 of the License, or
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+#----------------------------------------------------------------------
+# XMPP: echolib (im@echolib.re)
+#
+# Description: Manage show*/edit* arguments.
+# Read or edit file from [target] argument
+# File: /var/lib/tyto/program/show.py
+#----------------------------------------------------------------------
#------------
# funny stats
@@ -17,9 +34,64 @@
#**********************************************************************
-import os, sys, importlib
+import os, sys, locale, importlib
import args, lang, logs, dom, db, form, tyto, check, stats
+# load locale translation
+trans_dir = '/var/lib/tyto/translations'
+sys.path.insert(0, trans_dir)
+
+# System language
+try: lang_sys = locale.getdefaultlocale()[0].split('_')[0]
+except: lang_sys = 'en'
+
+# Get default system language
+# or set "en" (english) if no translation file
+try:
+ lang_site = lang_sys
+ os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
+except:
+ lang_site = 'en'
+
+# Set language site/form from configuration domain
+# or set default english if not known
+try:
+ dom.exists
+ lang_site = dom.lang_site
+ os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
+ tr = importlib.import_module('site_%s'%lang_site, package=None)
+except:
+ tr = importlib.import_module('site_%s'%lang_site, package=None)
+
+
+#========================#
+# Read lines from a file #
+# alone: True/False #
+#------------------------#
+def read_lines(f, alone):
+ if not f: return
+ if not tyto.exists(f): logs.out("1", f, True)
+
+ datas = open(f).read()
+
+ # Align content line, after line number
+ ln_datas = len(datas.splitlines()) + 1
+ sp_max = len(str(ln_datas))
+
+ print(' ├', f)
+ print(' ├─%s─┐'%(sp_max * '─'))
+ for ln, line in enumerate(datas.rsplit('\n'), 1):
+ sp = sp_max - len(str(ln))
+ print(' │ %s %s│ %s'%(ln, int(sp) * " ", line))
+
+ # Ends for show. False should be for form
+ if alone: decor = '└'
+ else: decor = '├'
+ print(' %s─%s─┘'%(decor, sp_max * '─'))
+
+ dom.valid()
+
+
#======================#
# From command line: #
# - 'showdb' / 'show' #
@@ -28,130 +100,126 @@ import args, lang, logs, dom, db, form, tyto, check, stats
# final html, db, load #
#----------------------#
def manage(target):
- # Domain must be valid
if not dom.exists: logs.out("10", '', True)
- if not target == "domain": dom.valid()
+ dom.valid()
- do = False
actions_read = ('show', 'show-about', 'show-db', 'show-wip', 'show-www')
actions_edit = ('edit', 'edit-about', 'edit-db', 'edit-wip', 'edit-www')
+ post_src = post_db = post_wip = post_www = False
- actions_about= ('show-about', 'edit-about')
- actions_wip = ('show-wip', 'edit-wip')
- actions_www = ('show-www', 'edit-www')
-
- actions_post = ('show', 'edit')
- actions_db = ('show-db', 'edit-db')
-
- # Target is not a post uri (sidebar, navbar, metas, footer)
- #----------------------------------------------------------
- if target in args.pass_targets:
- if args.action in actions_post:
- do = {
- "domain" : dom.config,
- "footer" : dom.footer_f,
- "metas" : dom.metas_f,
- "navbar" : dom.navbar_f,
- "sidebar" : dom.sidebar_f
- }
-
- elif args.action in actions_about:
- do = {
- "footer" : dom.footer_about_f
- }
-
- elif args.action in actions_wip:
- if target == 'stats':
- stats.manage_stats('wip')
- return
+ # Set file from post DB when target is an article
+ #------------------------------------------------
+ try: post_src = db.uri_file
+ except: pass
- do = {
- "domain" : dom.config,
- "footer" : dom.wip_footer_f,
- "metas" : dom.wip_metas_f,
- "navbar" : dom.wip_navbar_f,
- "sidebar" : dom.wip_sidebar_f
- }
+ if post_src:
+ target = "post"
+ try: post_db = db.config
+ except: pass
- elif args.action in actions_www:
- if target == 'stats':
- stats.manage_stats('www')
- return
-
- do = {
- "domain" : dom.config,
- "footer" : dom.www_footer_f,
- "metas" : dom.www_metas_f,
- "navbar" : dom.www_navbar_f,
- "sidebar" : dom.www_sidebar_f
- }
-
- # Target is a post uri
- #---------------------
- elif db.uri_file:
+ try: post_wip = db.post_wip
+ except: pass
- # Get hash when edit, and ask if file changed
+ try: post_www = db.post_www
+ except: pass
+
+ # Except for show-about > Show post DB
+ if args.action == "show-about":
+ target = 'post'
+
+ # When edit article, get src hash
if args.action == "edit":
curr_hash = tyto.get_filesum(db.uri_file, True)
-
- if args.action in actions_post:
- target = "post"
- do = {"post" : db.uri_file}
-
- # Post has database
- elif db.exists:
- do = {
- "db" : db.config,
- "wip" : db.post_wip,
- "www" : db.post_www
- }
- if args.action in actions_wip: target = "wip"
- elif args.action in actions_www: target = "www"
- elif args.action in actions_db: target = "db"
+
+
+ # Convert command action to do[]
+ # as edit* &nd show* [action] have same target file
+ actions = \
+ {
+ 'show' : 'src',
+ 'edit' : 'src',
+ 'post' : 'src',
+ 'show-db' : 'db',
+ 'edit-db' : 'db',
+ 'show-about' : 'about',
+ 'edit-about' : 'about',
+ 'show-wip' : 'wip',
+ 'edit-wip' : 'wip',
+ 'show-www' : 'www',
+ 'edit-www' : 'www'
+ }
+ action = actions[args.action]
- #print('> show: target', target)
-
- if not do:
- if not db.post: sys.exit(1)
-
-
- # Read lines of, or edit file
- if args.action in actions_read: read_lines(do[target])
- elif args.action in actions_edit: tyto.edit_file(do[target])
+ # Set target file from "new" [action]
+ do = \
+ {
+ 'src' : {
+ 'domain' : dom.config,
+ 'footer' : dom.footer_f,
+ 'metas' : dom.metas_f,
+ 'navbar' : dom.navbar_f,
+ 'sidebar' : dom.sidebar_f,
+ 'post' : post_src
+ },
+ 'db' : {
+ 'domain' : dom.config,
+ 'footer' : dom.footer_f,
+ 'metas' : dom.metas_f,
+ 'navbar' : dom.navbar_f,
+ 'sidebar' : dom.sidebar_f,
+ 'post' : post_db
+ },
+ 'about' : {
+ 'domain' : dom.config,
+ 'footer' : dom.footer_about_f,
+ 'metas' : dom.metas_f,
+ 'navbar' : dom.navbar_f,
+ 'sidebar' : dom.sidebar_f,
+ 'post' : post_db
+ },
+ 'wip' : {
+ 'domain' : dom.config,
+ 'footer' : dom.wip_footer_f,
+ 'metas' : dom.wip_metas_f,
+ 'navbar' : dom.wip_navbar_f,
+ 'sidebar' : dom.wip_sidebar_f,
+ 'post' : post_wip
+ },
+ 'www' : {
+ 'domain' : dom.config,
+ 'footer' : dom.www_footer_f,
+ 'metas' : dom.www_metas_f,
+ 'navbar' : dom.www_navbar_f,
+ 'sidebar' : dom.www_sidebar_f,
+ 'post' : post_www
+ },
+ }
- # After editing article, if change, ask to check again
- if args.action == "edit" and not args.pass_targets:
- new_hash = tyto.get_filesum(db.uri_file, True)
+ # Read or edit file, according to legacy args.action
+ try:
+ file = do[action][target]
+ if args.action in actions_read:
+ read_lines(file, True)
+ elif args.action in actions_edit:
+ tyto.edit_file(file)
+ except:
+ logs.out("28", '%s + %s'%(action, target), True)
+
+
+ # If edit article and hash changed, ask to check
+ if args.action == "edit" and post_src:
+ new_hash = tyto.get_filesum(post_src, True)
if curr_hash != new_hash:
ask = ''
- try: ask = input('-> Check your changes ? ')
+ try: ask = input(' ├ %s%s '%(tr.post_chg, tr.q))
except KeyboardInterrupt:
print('')
logs.out("255", '', True)
- if not ask in ['y', 'Y']:
+ if not ask in form.answer_yes:
logs.out("255", '', True)
# Reload post DB (if edited article, and check it if ask "y")
importlib.reload(db)
- check.manage_check(db.uri_file)
-
-
-#============================================#
-# Generic function to read lines from a file #
-#--------------------------------------------#
-def read_lines(f):
- if not f: return # Maybe
- if not tyto.exists(f): logs.out("1", f, True)
+ check.manage(post_src)
- datas = open(f).read()
-
- # Align content line, after line number
- ln_datas = len(datas.splitlines()) + 1
- sp_max = len(str(ln_datas))
-
- for ln, line in enumerate(datas.rsplit('\n'), 1):
- sp = sp_max - len(str(ln))
- print(' │ %s %s│ %s'%(ln, int(sp) * " ", line))
-
- dom.valid()
diff --git a/src/var/lib/tyto/program/tyto.py b/src/var/lib/tyto/program/tyto.py
index 295f4cf..c3b01f2 100644
--- a/src/var/lib/tyto/program/tyto.py
+++ b/src/var/lib/tyto/program/tyto.py
@@ -135,14 +135,22 @@ words_tags = [
('-(', '-)', '-(', '-)', 'lists', 't')
]
+# Tags that do not need to be paired
+#-----------------------------------
+single_tags = [
+('|', '
'), # New Line
+('->', '') # Anchors
+]
+
# When counting words, do no count line starting with:
nolinewords = \
(
-'((', '))',
-'{{', ']]',
-'{{', '}}',
-'->', '|',
-'_image:', '_taw:'
+words_tags[10][0], words_tags[10][1], # paragraphs
+words_tags[11][0], words_tags[11][1], # quotes
+words_tags[12][0], words_tags[12][1], # bcodes
+words_tags[13][0], words_tags[13][1], # lists
+single_tags[0][0], single_tags[1][0], # New line, anchor
+'_%s:'%opt_header_tags[1], '_%s:'%opt_header_tags[4] # _image:, _raw:
)
# warning symbols (Check if paired)
@@ -156,16 +164,9 @@ tpl_tags = [
]
-# Tags that do not need to be paired
-#-----------------------------------
-single_tags = [
-('|', '
'), # New Line
-('->', '') # Anchors
-]
-
# Markers for lists, to check in list content
#--------------------------------------------
-markers_lists = ('+', '=', ' ')
+markers_lists = ('+', '=', ' ', '#')
# Tags used for titles
#---------------------
@@ -335,23 +336,34 @@ def protect_bcodes_quotes(process, post_bottom):
b64_quote = b64('Encode', quote, 'Q64.', '.Q64')
line = b64_quote
+ '''
+ # Remove coemments and empty lines for wip
if not in_quote and not in_bcode:
- if not line: continue
+ if not line:
+ continue
if line.startswith('#') and not line.startswith(titles_tags):
continue
-
+ '''
# Counters and keep tags for check process
#-----------------------------------------
if process == "check":
if in_bcode and not start_bcode \
or in_quote and not start_quote :
- continue
+ line = '#-Protectedline-'
# Set new article content for wip process
#----------------------------------------
elif process == "wip":
+ # Remove empty line and comments
+ if not in_quote and not in_bcode:
+ if not line:
+ continue
+ elif line.startswith('#') \
+ and not line.startswith(titles_tags):
+ continue
+
# bcode convertion to base64
if in_bcode:
# Convert lines to b64
@@ -369,7 +381,6 @@ def protect_bcodes_quotes(process, post_bottom):
#----------------
# check: remove quote/bcode, keep tags
# wip: replace close tag with quote/bcode (keep in open tag)
- if not line: continue
if not protect_article: protect_article = line
else: protect_article = '%s\n%s'%(protect_article, line)
@@ -498,34 +509,43 @@ def replace_in_db(post_db, process, hash_post):
# Copy files used by article to srv #
#-----------------------------------#
def files_to_srv(server):
+ import db
for uri in db.uris:
+
+ # Extract Directories from uri file
+ d_in = uri.split("/")[-1]
+ d_in = uri.rsplit(d_in)[0]
+
# Destination file to server
- f_src = '%s%s'%(db.domain_articles, uri)
- if server == 'wip': f_dst = '%s%s'%(db.srv_wip, uri)
- elif server == 'www': f_dst = '%s%s'%(db.srv_www, uri)
+ f_src = '%s%s'%(dom.articles_d[:-1], uri)
+ if server == 'wip':
+ f_dst = '%s%s'%(dom.srv_wip[:-1], uri)
+ d_dst = '%s%s'%(dom.srv_wip[:-1], d_in)
+ elif server == 'www':
+ f_dst = '%s%s'%(dom.srv_www[:-1], uri)
+ d_dst = '%s%s'%(dom.srv_www[:-1], d_in)
# Create folder and subfolders
- f_uri = uri.split("/")[-1]
- f_uri = uri.rsplit(f_uri)[0]
try:
- os.makedirs('%s%s'%(f_dst, f_uri), exist_ok=True)
+ os.makedirs(d_dst, exist_ok=True)
+ logs.out("33", d_dst, False)
except:
- logs.out('4', '%s%s'%(f_dst, f_uri), True)
+ logs.out('4', d_dst, True)
try:
shutil.copy2(f_src, f_dst)
- logs.out("33", f_dst, False)
+ logs.out("32", f_dst, False)
except:
logs.out('4', f_dst, True)
- if db.article_code:
- if server == "wip": base_srv = db.srv_wip
- elif server == "www": base_srv = db.srv_www
+ if dom.article_code:
+ if server == "wip": base_srv = dom.srv_wip
+ elif server == "www": base_srv = dom.srv_www
f_dst = "%s%s"%(base_srv, db.short_src)
try:
shutil.copy2(db.post_src, f_dst)
- logs.out("33", f_dst, False)
+ logs.out("32", f_dst, False)
except:
logs.out('4', f_dst, True)
diff --git a/src/var/lib/tyto/program/wip.py b/src/var/lib/tyto/program/wip.py
index 43ac736..6d84b9a 100644
--- a/src/var/lib/tyto/program/wip.py
+++ b/src/var/lib/tyto/program/wip.py
@@ -1,11 +1,30 @@
#!/usr/bin/env python3
-# Name: Tyto - Littérateur
-# Type: Convert article to HTML
-# Description: Converters from Source to HTML
-# file: wip.py
-# Folder: /var/lib/tyto/program/
-# By echolib (XMPP: im@echolib.re)
-# License: GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007
+# Tyto - Littérateur
+#
+# Copyright (C) 2023 Cyrille Louarn
+# Copyright (C) 2023 Adrien Bourmault
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License
+# as published by the Free Software Foundation, either version 3 of the License, or
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+#----------------------------------------------------------------------
+# XMPP: echolib (im@echolib.re)
+# XMPP: neox (neox@a-lec.org)
+#
+# Description: Manage 'wip' argument
+# Convert article to HTML from Tyto's format markers
+# File: /var/lib/tyto/program/wip.py
+#----------------------------------------------------------------------
#------------
# funny stats
@@ -17,10 +36,36 @@
#**********************************************************************
-import os, re, sys, shutil, importlib
+import os, re, sys, locale, shutil, importlib, time
from pathlib import Path
-import args, logs, dom, db, tyto, html, form, stats
+import args, logs, lang, dom, db, tyto, html, form, stats
+
+# load locale translation
+trans_dir = '/var/lib/tyto/translations'
+sys.path.insert(0, trans_dir)
+
+# System language
+try: lang_sys = locale.getdefaultlocale()[0].split('_')[0]
+except: lang_sys = 'en'
+
+# Get default system language
+# or set "en" (english) if no translation file
+try:
+ lang_site = lang_sys
+ os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
+except:
+ lang_site = 'en'
+
+# Set language site/form from configuration domain
+# or set default english if not known
+try:
+ dom.exists
+ lang_site = dom.lang_site
+ os.path.exists('%s/site_%s.py'%(trans_dir, lang_site))
+ tr = importlib.import_module('site_%s'%lang_site, package=None)
+except:
+ tr = importlib.import_module('site_%s'%lang_site, package=None)
#=========================================#
@@ -55,10 +100,10 @@ def manage_wip(target):
# Per article with target
#------------------------
# Exit with these conditions
- if not target: logs.out("5", '', True)
- if not db.post_exists: sys.exit(1)
- if not db.db_exists: logs.out("25", db.uri_file, True)
- if db.old_chk: logs.out("9", db.uri_file, True)
+ if not target: logs.out("5", '', True)
+ if not db.exists: sys.exit(1)
+ if not db.config: logs.out("25", db.uri_file, True)
+ if db.old_chk: logs.out("9", db.uri_file, True)
# Article has changed or wip file missing
if db.old_wip or not db.file_wip:
@@ -68,12 +113,14 @@ def manage_wip(target):
else:
logs.out("19", db.date_wip, False)
try:
- res = input(' ├ Create new wip page ? ')
+ res = input(' ├ [%s] %s%s '%(db.title, tr.wip_new, tr.q))
except KeyboardInterrupt:
print('')
logs.out("255", '', True)
- if not res in ['y', 'Y']: return
+ if not res in form.answer_yes:
+ logs.out("255", '', True)
+
wip_article(db.uri_file)
@@ -85,7 +132,7 @@ def wip_all(process):
tyto.process_all('Wip')
# Sort by newer articles (created by last check)
- db_articles = sorted(Path(db.articles_db).iterdir(),
+ db_articles = sorted(Path(db.articles_db_d).iterdir(),
key=os.path.getmtime
)
@@ -93,7 +140,7 @@ def wip_all(process):
option = args.target
found = False
for post_db in db_articles:
- if not str(post_db).endswith('.conf'): continue
+ if not str(post_db).endswith('.config'): continue
# Load DB
exec(open(post_db).read(),globals())
@@ -104,7 +151,7 @@ def wip_all(process):
if option == "again" and db.old_wip: continue
if option == "newer" and not db.old_wip: continue
- print(':> [%s] - %s'%(db.title, db.post_src))
+ print(' ├ [%s] > %s'%(db.title, db.post_src))
if db.old_chk:
logs.out("9", '', False)
continue
@@ -127,14 +174,14 @@ def wip_article(target):
global post_bottom
# Protect block-codes and quotes
- if db.stat_bcodes or db.stat_quotes > 0:
+ if db.post_bcodes or db.post_quotes > 0:
tyto.protect_bcodes_quotes('wip', post_bottom)
post_bottom = tyto.protect_article
# Protect inline-codes
- if db.stat_icodes > 0:
+ if db.post_icodes > 0:
tyto.protect_icodes(post_bottom)
- post_bottom = tyto.protect_article
+ post_bottom = tyto.protect_article
# Convert contents from modules
@@ -151,16 +198,17 @@ def wip_article(target):
wip_tabs() # make HTML tabulations
# Replace in DB hash_wip and date_wip
- tyto.replace_in_db(db.post_db, 'wip', db.hash_post)
+ tyto.replace_in_db(db.config, 'wip', db.hash_post)
# Get article DB in html.py
html.set_page(db.uri_file, post_bottom)
#print(html.main_page)
# Create wip file
- os.makedirs('%s%s'%(db.srv_wip, db.direc_src), exist_ok=True)
+ os.makedirs('%s%s'%(dom.srv_wip, db.direc_src), exist_ok=True)
+ logs.out("33", '%s%s'%(dom.srv_wip, db.direc_src), False)
tyto.set_file(db.post_wip, 'New', html.main_page)
- logs.out("33", db.post_wip, False)
+ logs.out("32", db.post_wip, False)
# Copy needed files (Also create sub-folders)
tyto.files_to_srv('wip')
@@ -182,8 +230,9 @@ def file_to_string(post_file):
continue
if sep:
- if not post_bottom: post_bottom = line
- else: post_bottom = '%s\n%s'%(post_bottom, line)
+ if not line: continue
+ elif not post_bottom: post_bottom = line
+ else: post_bottom = '%s\n%s'%(post_bottom, line)
else:
if not post_header: post_header = line
else: post_header = '%s\n%s'%(post_header, line)
@@ -237,7 +286,7 @@ def wip_words_tags():
for ln, line in enumerate(post_bottom.rsplit('\n')):
# Paragraphs
# Open tag
- if db.stat_paragraphs > 0:
+ if db.post_paragraphs > 0:
if line.startswith(tyto.words_tags[10][0]):
set_css = tyto.get_css(line)
post_bottom = post_bottom.replace(post_bottom.rsplit('\n')[ln],
@@ -249,7 +298,8 @@ def wip_words_tags():
tyto.words_tags[10][3]
)
# Open anchors
- if db.stat_anchors == 0: continue
+ if db.post_anchors == 0: continue
+
anchor_links = re.findall(r'>_(.+?):', line)
for item in anchor_links:
anchor_id = '%s%s:'%(tyto.words_tags[0][0], item)
@@ -333,7 +383,7 @@ def wip_images():
for i in range(1, db.uniq_images + 1):
image = 'db.image_%s'%i
target = width = height = False
- set_css = db.domain_css + '_image'
+ set_css = dom.css + '_image'
imag_html = ''
if eval(image)[0] == values[0]:
@@ -401,7 +451,7 @@ def quote_params(qline):
# Convert quote in article #
#--------------------------#
def wip_quotes() :
- if db.stat_quotes == 0: return
+ if db.post_quotes == 0: return
global post_bottom
global author, link, lang, book, date
@@ -545,7 +595,7 @@ def wip_quotes() :
# Content is HTML ready #
#--------------------------#
def wip_icodes():
- if db.stat_icodes == 0: return
+ if db.post_icodes == 0: return
global post_bottom
@@ -561,7 +611,7 @@ def wip_icodes():
# Content is raw, and have to be converted in HTML #
#--------------------------------------------------#
def wip_bcodes():
- if db.stat_bcodes == 0: return
+ if db.post_bcodes == 0: return
global post_bottom
@@ -595,7 +645,7 @@ def wip_bcodes():
# Check between titles to set div or not #
#----------------------------------------#
def wip_titles():
- if db.stat_titles == 0: return
+ if db.post_titles == 0: return
global post_bottom
article_temp = post_bottom
@@ -740,3 +790,94 @@ def wip_tabs():
post_bottom = article_temp
+
+#=================================#
+# Convert list in markers to HTML #
+# Def from neox <- Thx a lot #
+#---------------------------------#
+def convert_list(markdown_str):
+
+ # First step : reshape lines
+
+ items = []
+ inside_item = 0
+ index = -1
+
+ # Cut string with \n's
+ strlist = markdown_str.split("\n")
+
+ # Find items
+ for i in range(len(strlist)):
+ if "-(" in strlist[i] or "-)" in strlist[i]:
+ continue
+
+ if strlist[i][0] != "=" and strlist[i][0] != "+":
+ if inside_item != 1:
+ inside_item = 1
+ else:
+ inside_item = 0
+
+ if inside_item == 0:
+ items.append(strlist[i])
+ index += 1
+
+ if inside_item == 1:
+ items[index] += strlist[i].lstrip()
+
+ #print("[{}] index {}, inside_item {}, curstr {}\n".format(i, index, inside_item, strlist[i]))
+
+ # Second step : parsing
+ UL = 1
+ OL = 2
+ CLOSING = ["ERROR", "\n", "\n"]
+ OPENING = ["ERROR", "\n", "\n"]
+
+ rank_stack = []
+ rank = 0
+ cur_rank = 0
+ state = 0
+ old_state = 0
+ work_str = ""
+
+ for i in range(len(items)):
+ if "-(" in items[i] or "-)" in items[i]:
+ continue
+ rank = cur_rank
+ descriptor = items[i].split(" ")[0]
+ text = items[i][items[i].find(" "):]
+ cur_rank = len(descriptor)
+
+ if "=" in descriptor:
+ state = UL
+ elif "+" in descriptor:
+ state = OL
+ else:
+ raise(Exception)
+
+ # rank up
+ if cur_rank > rank:
+ for i in range(cur_rank - rank - 1):
+ work_str += " "*(rank+i) + OPENING[rank_stack.append(UL)]
+ rank_stack.append(state)
+
+ work_str += " "*rank + OPENING[state]
+
+ # rank down
+ elif cur_rank < rank:
+ for i in range(rank - cur_rank - 1):
+ work_str += " "*(rank-i-1) + CLOSING[rank_stack.pop()]
+
+ work_str += " "*cur_rank + CLOSING[rank_stack.pop()]
+
+
+ work_str += " "*cur_rank + "- " + text + "
\n"
+
+ print("[{}] rank_stack {}, state {}, old_state {}, rank {}, cur_rank {}, text {}\n".format(
+ i, rank_stack, state, old_state, rank, cur_rank, text))
+
+ work_str += " "*(cur_rank-1) + CLOSING[rank_stack.pop()]
+
+ return(work_str)
+
+
+#print(convert_list(str_exemple))
diff --git a/src/var/lib/tyto/translations/site_en.py b/src/var/lib/tyto/translations/site_en.py
index 23b83b8..163bb06 100644
--- a/src/var/lib/tyto/translations/site_en.py
+++ b/src/var/lib/tyto/translations/site_en.py
@@ -59,10 +59,15 @@ mail_to = "Contact by %s the admin of"%mail.lower()
feed = "Feed"
generator = "Generator"
+# Check
+post_chg = "Article was edited. Check it"
+
+# Wip
+wip_new = "Create new HTML page in wip"
+
# Form
#----------------------------------------------------------------------
form_edit = "Edit the domain with the form"
-
form_start = ' ├──────────────────────────────────────────────┐\n' + \
' │ Configure a new domain for current directory │\n' + \
' │ Answer Y/y = yes. Enter to keep {default} │\n' + \
diff --git a/src/var/lib/tyto/translations/site_fr.py b/src/var/lib/tyto/translations/site_fr.py
index 783ea43..72051a6 100644
--- a/src/var/lib/tyto/translations/site_fr.py
+++ b/src/var/lib/tyto/translations/site_fr.py
@@ -59,6 +59,12 @@ mail_to = "Contacter par %s l'administrateur de"%mail.lower()
feed = "Flux"
generator = "Generateur"
+# Check
+post_chg = "Article édité. Le vérifier"
+
+# Wip
+wip_new = "Créer une nouvelle page HTML dans wip"
+
# Formulaire
#----------------------------------------------------------------------
form_edit = "Éditer le domaine avec le formulaire"