Goodbye bacon!

This commit is contained in:
Geoffrey Frogeye 2018-10-06 10:27:36 +02:00
parent d010c48306
commit 4f02db850b
15 changed files with 423 additions and 204 deletions

View file

@ -5,5 +5,4 @@ echo $(for i in "" "%20Bold" "%20Oblique" "%20Bold%20Oblique"; do
cd $HOME/.local/share/fonts
wget -c http://raw.githubusercontent.com/powerline/fonts/master/DejaVuSansMono/DejaVu%20Sans%20Mono$i%20for%20Powerline.ttf
done)
wget -c "https://aur.archlinux.org/cgit/aur.git/plain/icons.ttf?h=ttf-font-icons" -O $HOME/.local/share/fonts/icons.ttf
wget -c "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/a8386aae19e200ddb0f6845b5feeee5eb7013687/fonts/fontawesome-webfont.ttf" -O $HOME/.local/share/fonts/fontawesome-webfont.ttf

View file

@ -64,8 +64,8 @@ bindsym $mod+F11 exec urxvtc -e 'pacmixer'
bindsym $mod+F12 exec urxvtc -e 'pacmixer'
#Brightness control
bindsym XF86MonBrightnessDown exec xbacklight -dec 20
bindsym XF86MonBrightnessUp exec xbacklight -inc 20
bindsym XF86MonBrightnessDown exec xbacklight -dec 20 -time 0
bindsym XF86MonBrightnessUp exec xbacklight -inc 20 -time 0
# Screenshots
bindsym Print exec scrot -ue 'mv $f ~/Screenshots/'
@ -226,13 +226,6 @@ bindsym $mod+ctrl+shift+Left move workspace to output left
bindsym $mod+Ctrl+Shift+Up move workspace to output above
bindsym $mod+Ctrl+Shift+Down move workspace to output below
# Open applications on specific workspaces
assign [class="Thunderbird"] $WS7
assign [class="Skype"] $WS7
assign [class="Pidgin"] $WS7
assign [class="Clementine"] $WS10
assign [title="TweetDeck"] $WS8
# Open specific applications in floating mode
for_window [title="pacmixer"] floating enable border pixel 2
for_window [class="Firefox"] layout tabbed
@ -353,6 +346,7 @@ set_from_resource $color15 i3wm.color15 #cfd0c2
# Inactivity settings
exec --no-startup-id xautolock -time 10 -locker 'xset dpms force standby' -killtime 1 -killer '$locker'
bindsym $mod+F1 exec --no-startup-id xset dpms force off
bindsym $mod+F4 exec --no-startup-id xautolock -disable
bindsym $mod+F5 exec --no-startup-id xautolock -enable
@ -366,7 +360,7 @@ exec --no-startup-id unclutter -root # Hide mouse cursor after some time
#exec --no-startup-id dunst # Notifications (handled by systemd)
exec --no-startup-id keynav # Keyboard cursor controller
#exec --no-startup-id mpd # Music Player Daemon (handled by systemd)
exec --no-startup-id ~/.config/i3/ashuffle # MPD Auto-refill
# exec --no-startup-id ~/.config/i3/ashuffle # MPD Auto-refill
exec --no-startup-id autorandr --change # Screen configuration and everything that depends on it
exec --no-startup-id ~/.config/i3/batteryNotify -d # Battery state notification
@ -381,3 +375,7 @@ client.urgent $color01 $color01 $color07 $foreground $color09
client.placeholder $ignore $color06 $color07 $ignore $color14
client.background $color15
# bar {
# i3bar_command ~/.config/lemonbar/bar.py
# }

View file

@ -25,6 +25,7 @@ if __name__ == "__main__":
Bar.addSectionAll(MpdProvider(theme=7), BarGroupType.LEFT)
# Bar.addSectionAll(I3WindowTitleProvider(), BarGroupType.LEFT)
# TODO Computer modes
SYSTEM_THEME = 2
DANGER_THEME = FOCUS_THEME
@ -40,6 +41,7 @@ if __name__ == "__main__":
# TODO Disk space provider
# TODO Screen (connected, autorandr configuration, bbswitch) provider
Bar.addSectionAll(PulseaudioProvider(theme=PERIPHERAL_THEME), BarGroupType.RIGHT)
Bar.addSectionAll(RfkillProvider(theme=PERIPHERAL_THEME), BarGroupType.RIGHT)
Bar.addSectionAll(NetworkProvider(theme=NETWORK_THEME), BarGroupType.RIGHT)
# Personal
@ -50,3 +52,5 @@ if __name__ == "__main__":
TIME_THEME = 6
Bar.addSectionAll(TimeProvider(theme=TIME_THEME), BarGroupType.RIGHT)
# Bar.run()

View file

@ -3,6 +3,9 @@
import enum
import threading
import time
import i3ipc
import os
import signal
import subprocess
import logging
import coloredlogs
@ -10,6 +13,7 @@ import coloredlogs
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
log = logging.getLogger()
# TODO Allow deletion of Bar, BarGroup and Section for screen changes
# IDEA Use i3 ipc events rather than relying on xrandr or Xlib (less portable
# but easier)
@ -18,6 +22,7 @@ log = logging.getLogger()
# TODO Use bytes rather than strings
# TODO Use default colors of lemonbar sometimes
# TODO Adapt bar height with font height
# TODO OPTI Static text objects that update its parents if modified
class BarGroupType(enum.Enum):
@ -30,7 +35,7 @@ class BarGroupType(enum.Enum):
class BarStdoutThread(threading.Thread):
def run(self):
while True:
while Bar.running:
handle = Bar.process.stdout.readline().strip()
if not len(handle):
continue
@ -52,6 +57,7 @@ class Bar:
@staticmethod
def init():
Bar.running = True
Section.init()
cmd = ['lemonbar', '-b', '-a', '64']
@ -66,10 +72,35 @@ class Bar:
Bar(0)
# Bar(1)
@staticmethod
def stop():
Bar.running = False
Bar.process.kill()
# TODO This is not really the best way to do it I guess
os.killpg(os.getpid(), signal.SIGTERM)
@staticmethod
def run():
Bar.forever()
i3 = i3ipc.Connection()
def doStop(*args):
Bar.stop()
print(88)
try:
i3.on('ipc_shutdown', doStop)
i3.main()
except BaseException:
print(93)
Bar.stop()
# Class globals
everyone = set()
string = ""
process = None
running = False
nextHandle = 0
actionsF2H = dict()
@ -92,8 +123,11 @@ class Bar:
@staticmethod
def forever():
try:
while True:
time.sleep(60)
except BaseException:
Bar.stop()
def __init__(self, screen):
assert isinstance(screen, int)
@ -136,6 +170,7 @@ class Bar:
@staticmethod
def updateAll():
if Bar.running:
Bar.string = ""
for bar in Bar.everyone:
bar.update()
@ -276,11 +311,14 @@ class SectionThread(threading.Thread):
class Section:
# TODO Update all of that to base16
COLORS = ['#002b36', '#dc322f', '#859900', '#b58900', '#268bd2', '#6c71c4',
'#2aa198', '#93a1a1', '#657b83', '#dc322f', '#859900', '#b58900',
'#268bd2', '#6c71c4', '#2aa198', '#fdf6e3']
FGCOLOR = '#93a1a1'
BGCOLOR = '#002b36'
# COLORS = ['#272822', '#383830', '#49483e', '#75715e', '#a59f85', '#f8f8f2',
# '#f5f4f1', '#f9f8f5', '#f92672', '#fd971f', '#f4bf75', '#a6e22e',
# '#a1efe4', '#66d9ef', '#ae81ff', '#cc6633']
COLORS = ['#181818', '#AB4642', '#A1B56C', '#F7CA88', '#7CAFC2', '#BA8BAF',
'#86C1B9', '#D8D8D8', '#585858', '#AB4642', '#A1B56C', '#F7CA88',
'#7CAFC2', '#BA8BAF', '#86C1B9', '#F8F8F8']
FGCOLOR = '#F8F8F2'
BGCOLOR = '#272822'
THEMES = list()
EMPTY = (FGCOLOR, BGCOLOR)
@ -357,6 +395,8 @@ class Section:
def updateText(self, text):
if isinstance(text, str):
text = Text(text)
elif isinstance(text, Text) and not len(text.elements):
text = None
self.dstText[0] = None if (text is None and not self.persistent) else ((' ' + self.icon + ' ') if self.icon else ' ')
self.dstText[1] = text
@ -373,6 +413,12 @@ class Section:
Section.sizeChanging.add(self)
Section.somethingChanged.set()
def setDecorators(self, **kwargs):
self.dstText.setDecorators(**kwargs)
self.curText = str(self.dstText)
self.informParentsTextChanged()
Section.somethingChanged.set()
def updateTheme(self, theme):
assert isinstance(theme, int)
assert theme < len(Section.THEMES)
@ -440,13 +486,14 @@ class Section:
class StatefulSection(Section):
# TODO FEAT Allow to temporary expand the section (e.g. when important change)
NUMBER_STATES = None
DEFAULT_STATE = 0
def __init__(self, *args, **kwargs):
Section.__init__(self, *args, **kwargs)
self.state = 0
self.state = self.DEFAULT_STATE
if hasattr(self, 'onChangeState'):
self.onChangeState(self.state)
self.dstText.setDecorators(clickLeft=self.incrementState,
self.setDecorators(clickLeft=self.incrementState,
clickRight=self.decrementState)
def incrementState(self):
@ -466,6 +513,9 @@ class StatefulSection(Section):
self.refreshData()
class ColorCountsSection(StatefulSection):
# TODO FEAT Blend colors when not expanded
# TODO FEAT Blend colors with importance of count
# TODO FEAT Allow icons instead of counts
NUMBER_STATES = 3
COLORABLE_ICON = '?'
@ -552,6 +602,8 @@ class Text:
nest('A' + number + ':' + handle.decode() + ':', 'A' + number)
for key, val in self.decorators.items():
if val is None:
continue
if key == 'fg':
reset = self.section.THEMES[self.section.theme][0]
nest('F' + getColor(val), 'F' + reset)

15
config/lemonbar/launch.sh Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env sh
# TODO Make this better
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
ex="$DIR/bar.py"
# Terminate already running bar instances
ps -af | grep "python3 $ex" | grep -v grep | awk '{print $2}' | while read p; do kill $p; done
killall -q lemonbar
$ex

View file

@ -18,6 +18,8 @@ import random
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
log = logging.getLogger()
# TODO Generator class (for I3WorkspacesProvider, NetworkProvider and later
# PulseaudioProvider and MpdProvider)
def humanSize(num):
"""
@ -43,6 +45,7 @@ class TimeProvider(StatefulSection, PeriodicUpdater):
"%d/%m %H:%M:%S",
"%a %d/%m/%y %H:%M:%S"]
NUMBER_STATES = len(FORMATS)
DEFAULT_STATE = 1
def fetcher(self):
now = datetime.datetime.now()
@ -114,13 +117,13 @@ class RamProvider(AlertingSection, PeriodicUpdater):
def fetcher(self):
mem = psutil.virtual_memory()
freePerc = 1-mem.percent/100
freePerc = mem.percent/100
self.updateLevel(freePerc)
if self.state < 1:
return None
text = Text(Section.ramp(freePerc))
text = Text(Section.ramp(1-freePerc))
if self.state >= 2:
freeStr = humanSize(mem.available)
text.append(freeStr)
@ -162,7 +165,8 @@ class TemperatureProvider(AlertingSection, PeriodicUpdater):
class BatteryProvider(AlertingSection, PeriodicUpdater):
NUMBER_STATES = 2
# TODO Support ACPID for events
NUMBER_STATES = 3
RAMP = ""
def fetcher(self):
@ -179,8 +183,15 @@ class BatteryProvider(AlertingSection, PeriodicUpdater):
if self.state < 1:
return
return Text('{:.0f}%'.format(bat.percent))
# TODO Time remaining (if the estimation is somewhat correct)
t = Text('{:.0f}%'.format(bat.percent))
if self.state < 2:
return t
h = int(bat.secsleft / 3600)
m = int((bat.secsleft - h * 3600) / 60)
t.append(" ({:d}:{:02d})".format(h, m))
return t
def __init__(self, theme=None):
AlertingSection.__init__(self, theme)
@ -189,10 +200,13 @@ class BatteryProvider(AlertingSection, PeriodicUpdater):
class PulseaudioProvider(Section, ThreadedUpdater):
class PulseaudioProvider(StatefulSection, ThreadedUpdater):
NUMBER_STATES = 3
DEFAULT_STATE = 1
def __init__(self, theme=None):
ThreadedUpdater.__init__(self)
Section.__init__(self, theme)
StatefulSection.__init__(self, theme)
self.pulseEvents = pulsectl.Pulse('event-handler')
self.pulseEvents.event_mask_set(pulsectl.PulseEventMaskEnum.sink)
@ -205,20 +219,32 @@ class PulseaudioProvider(Section, ThreadedUpdater):
sinks = []
with pulsectl.Pulse('list-sinks') as pulse:
for sink in pulse.sink_list():
vol = pulse.volume_get_all_chans(sink)
if vol > 1:
vol = 1
if sink.port_active.name == "analog-output-headphones":
icon = ""
elif sink.port_active.name == "analog-output-speaker":
icon = ""
icon = "" if sink.mute else ""
else:
icon = "?"
vol = pulse.volume_get_all_chans(sink)
fg = (sink.mute and '#333333') or (vol > 1 and '#FF0000') or None
ramp = "" if sink.mute else (" " + self.ramp(vol))
sinks.append(icon + ramp)
return " ".join(sinks)
t = Text(icon, fg=fg)
sinks.append(t)
if self.state < 1:
continue
if self.state < 2:
if not sink.mute:
ramp = " "
while vol >= 0:
ramp += self.ramp(vol if vol < 1 else 1)
vol -= 1
t.append(ramp)
else:
t.append(" {:2.0f}%".format(vol*100))
return Text(*sinks)
def loop(self):
self.pulseEvents.event_listen()
@ -230,6 +256,7 @@ class PulseaudioProvider(Section, ThreadedUpdater):
class NetworkProviderSection(StatefulSection, Updater):
NUMBER_STATES = 5
DEFAULT_STATE = 1
def actType(self):
self.ssid = None
@ -260,6 +287,8 @@ class NetworkProviderSection(StatefulSection, Updater):
return ipv4, ipv6
def fetcher(self):
self.icon = None
self.persistent = False
if self.iface not in self.parent.stats or \
not self.parent.stats[self.iface].isup or \
self.iface.startswith('lo'):
@ -364,6 +393,41 @@ class NetworkProvider(Section, PeriodicUpdater):
self.fetchData()
self.changeInterval(5)
class RfkillProvider(Section, PeriodicUpdater):
# TODO FEAT rfkill doesn't seem to indicate that the hardware switch is
# toggled
PATH = '/sys/class/rfkill'
def fetcher(self):
t = Text()
for device in os.listdir(self.PATH):
with open(os.path.join(self.PATH, device, 'soft'), 'rb') as f:
softBlocked = f.read().strip() != b'0'
with open(os.path.join(self.PATH, device, 'hard'), 'rb') as f:
hardBlocked = f.read().strip() != b'0'
if not hardBlocked and not softBlocked:
continue
with open(os.path.join(self.PATH, device, 'type'), 'rb') as f:
typ = f.read().strip()
fg = (hardBlocked and '#CCCCCC') or (softBlocked and '#FF0000')
if typ == b'wlan':
icon = ''
elif typ == b'bluetooth':
icon = ''
else:
icon = '?'
t.append(Text(icon, fg=fg))
return t
def __init__(self, theme=None):
PeriodicUpdater.__init__(self)
Section.__init__(self, theme)
self.changeInterval(5)
class SshAgentProvider(PeriodicUpdater):
def fetcher(self):
cmd = ["ssh-add", "-l"]
@ -405,6 +469,7 @@ class GpgAgentProvider(PeriodicUpdater):
self.changeInterval(5)
class KeystoreProvider(Section, MergedUpdater):
# TODO OPTI+FEAT Use ColorCountsSection and not MergedUpdater, this is useless
ICON = ''
def __init__(self, theme=None):
@ -412,8 +477,6 @@ class KeystoreProvider(Section, MergedUpdater):
Section.__init__(self, theme)
class NotmuchUnreadProvider(ColorCountsSection, InotifyUpdater):
# TODO OPTI Transform InotifyUpdater (watching notmuch folder should be
# enough)
COLORABLE_ICON = ''
def subfetcher(self):
@ -456,7 +519,6 @@ class TodoProvider(ColorCountsSection, InotifyUpdater):
COLORABLE_ICON = ''
def updateCalendarList(self):
print(459)
calendars = sorted(os.listdir(self.dir))
for calendar in calendars:
# If the calendar wasn't in the list
@ -473,7 +535,6 @@ class TodoProvider(ColorCountsSection, InotifyUpdater):
with open(path, 'r') as f:
self.colors[calendar] = f.read().strip()
self.calendars = calendars
print(475, self.calendars)
def __init__(self, dir, theme=None):
"""
@ -539,6 +600,9 @@ class I3WorkspacesProviderSection(Section):
else:
return self.parent.themeNormal
# TODO On mode change the state (shown / hidden) gets overriden so every
# tab is shown
def show(self):
self.updateTheme(self.selectTheme())
self.updateText(self.fullName if self.focused else self.shortName)
@ -553,10 +617,15 @@ class I3WorkspacesProviderSection(Section):
self.fullName = self.parent.customNames[name] \
if name in self.parent.customNames else name
def switchTo(self):
self.parent.i3.command('workspace {}'.format(self.shortName))
def __init__(self, name, parent):
Section.__init__(self)
self.parent = parent
self.setName(name)
self.setDecorators(clickLeft=self.switchTo)
def empty(self):
self.updateTheme(self.parent.themeNormal)
@ -564,7 +633,7 @@ class I3WorkspacesProviderSection(Section):
class I3WorkspacesProvider(Section, I3Updater):
# TODO Multi-screen
# TODO FEAT Multi-screen
def initialPopulation(self, parent):
"""
@ -674,10 +743,13 @@ class MpdProvider(Section, ThreadedUpdater):
self.start()
def fetcher(self):
cur = self.mpd.currentsong()
stat = self.mpd.status()
if not len(stat) or stat["state"] == "stop":
return None
cur = self.mpd.currentsong()
if not len(cur):
return ''
return None
infos = []

View file

@ -190,10 +190,16 @@ class ThreadedUpdaterThread(threading.Thread):
def __init__(self, updater, *args, **kwargs):
self.updater = updater
threading.Thread.__init__(self, *args, **kwargs)
self.looping = True
def run(self):
while True:
try:
while self.looping:
self.updater.loop()
except BaseException as e:
log.error("Error with {}".format(self.updater))
log.error(e, exc_info=True)
self.updater.updateText("")
class ThreadedUpdater(Updater):

View file

@ -76,7 +76,8 @@ enable-ipc = true
inherit = bar/base
modules-center = mpd
modules-right = cpu memory temperature mail todo vpncheck eth wlan bbswitch xbacklight volume battery shortdate
; modules-right = cpu memory temperature mail todo vpncheck eth wlan bbswitch xbacklight volume battery shortdate
modules-right = cpu memory temperature mail vpncheck eth wlan bbswitch xbacklight volume battery shortdate
tray-position = right
tray-padding = 2

View file

@ -1 +0,0 @@
/home/geoffrey/.local/share/systemd/user/mbsync.timer

View file

@ -1 +0,0 @@
/usr/lib/systemd/user/syncthing.service

View file

@ -1,31 +1,139 @@
#!/usr/bin/env python3
import os
import argparse
import coloredlogs
import logging
import os
import sys
parser = argparse.ArgumentParser(description="Place a folder in ~/Documents in ~/Documents/Archives and symlink it")
parser.add_argument('dir', metavar='DIRECTORY', type=str, help="The directory to archive")
parser.add_argument('-d', '--dry', action='store_true')
args = parser.parse_args()
coloredlogs.install(level='DEBUG', fmt='%(levelname)s %(message)s')
log = logging.getLogger()
# Coding conventions:
# No leading or trailing slashes. Let os.path.join do its job
# TODO Config arparse and pass args to the functions. No globals
# Finding directories
assert('HOME' in os.environ), "Home directory unknown"
docs = os.path.realpath(os.path.join(os.environ['HOME'], 'Documents'))
assert(os.path.isdir(docs)), "Documents folder not found"
arcs = os.path.join(docs, 'Archives')
assert(os.path.isdir(arcs)), "Archives folder not found"
assert 'HOME' in os.environ, "Home directory unknown"
DOCS = os.path.realpath(os.path.join(os.environ['HOME'], 'Documents'))
assert os.path.isdir(DOCS), "Documents folder not found"
ARCS = os.path.realpath(os.path.join(os.environ['HOME'], 'Archives'))
assert os.path.isdir(ARCS), "Archives folder not found"
def dirRange(relpath):
splits = relpath.split(os.path.sep)
res = list()
for p in range(len(splits)):
partPath = os.path.join(*splits[:p+1])
arcPath = os.path.join(os.path.join(ARCS, partPath))
docPath = os.path.join(os.path.join(DOCS, partPath))
res.append((docPath, arcPath))
return res
def travel(relpath):
"""
Dunno what this will do, let's write code and see.
"""
wholeRange = dirRange(relpath)
for tup in wholeRange:
isLast = wholeRange[-1] == tup
docPath, arcPath = tup
linkPath = os.path.relpath(arcPath, start=docPath)
log.debug(f"47 {tup}")
if not os.path.exists(docPath) and not os.path.exists(arcPath):
log.error("Not existing")
sys.exit(1)
elif os.path.isdir(docPath) and os.path.isdir(arcPath) and not isLast:
log.debug("Both folder")
continue
elif os.path.isdir(docPath) and os.path.isdir(arcPath) and isLast:
log.error("This should fail for some reason, maybe")
sys.exit(1)
elif os.path.islink(docPath) and os.path.exists(arcPath):
currentLink = os.readlink(docPath)
if currentLink != linkPath:
log.warning(f"'{docPath}' is pointing to '{currentLink}' " +
f"but should point to '{linkPath}'.")
# TODO Fixing if asked for
sys.exit(1)
log.debug("Early link already exists {docPath} → {arcPath}")
return
elif not os.path.exists(docPath) and os.path.exists(arcPath):
log.debug("Only existing on archive side, linking")
print(f"ln -s {linkPath} {docPath}")
elif os.path.exists(docPath) and not os.path.exists(arcPath) \
and isLast:
log.debug("Only existing on doc side, moving and linking")
print(f"mv {docPath} {arcPath}")
print(f"ln -s {linkPath} {docPath}")
elif os.path.exists(docPath) and not os.path.exists(arcPath) \
and not isLast:
raise NotImplementedError("Here comes the trouble")
else:
log.error("Unhandled case")
sys.exit(1)
def ensureLink(relpath):
"""
Ensure that ~/Documents/$relpath points to ~/Archives/$relpath
"""
arcPath = os.path.join(os.path.join(ARCS, relpath))
docPath = os.path.join(os.path.join(DOCS, relpath))
assert os.path.exists(arcPath)
# For each tree element of the path
for docPath, arcPath in dirRange(relpath):
linkPath = os.path.relpath(arcPath, start=docPath)
def installLink():
if args.dry:
print(f"ln -s {linkPath} {docPath}")
else:
os.symlink(linkPath, docPath)
if os.path.islink(docPath):
currentLink = os.readlink(docPath)
if currentLink != linkPath:
log.warning(f"'{docPath}' is pointing to '{currentLink}' " +
f"but should point to '{linkPath}'. Fixing")
if args.dry:
print(f"rm {docPath}")
else:
os.unlink(docPath)
installLink()
return
elif not os.path.exists(docPath):
installLink()
return
elif os.path.isdir(docPath):
continue
else:
raise RuntimeError(f"'{docPath}' exists and is not a directory " +
f"or a link. Unable to link it to '{linkPath}'")
raise RuntimeError(f"'{docPath}' is a directory. Unable to link it to " +
f"'{linkPath}'")
def archive(docdir):
docdir = os.path.realpath(args.dir)
assert(os.path.isdir(docdir)), docdir + " must be a directory"
assert os.path.isdir(docdir), docdir + " must be a directory"
assert(docdir.startswith(docs)), "Directory is not in the document folder"
assert(not docdir.startswith(arcs)), "Directory is already in the archive folder"
assert docdir.startswith(DOCS), "Directory is not in the document folder"
assert not docdir.startswith(ARCS), "Directory is already in the archive folder"
reldir = os.path.relpath(docdir, docs)
reldir = os.path.relpath(docdir, DOCS)
print("ARC", reldir)
arcdir = os.path.join(arcs, reldir)
arcdir = os.path.join(ARCS, reldir)
parentArcdir = os.path.realpath(os.path.join(arcdir, '..'))
parentDocdir = os.path.realpath(os.path.join(docdir, '..'))
linkDest = os.path.relpath(arcdir, parentDocdir)
@ -36,7 +144,7 @@ def archive(docdir):
if os.path.isdir(arcdir):
return
# for f in os.listdir(arcdir):
# assert(os.path.isdir(f)), "Something unknown in Archive dir")
# assert os.path.isdir(f), "Something unknown in Archive dir")
# archive(os.path.join(arcdir, f))
# If the directory doesn't exist, create the directories under it and move all the folder
@ -58,8 +166,17 @@ def archive(docdir):
os.symlink(linkDest, docdir)
def unarchive(arcdir):
return
pass
archive(args.dir)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Place a folder in ~/Documents in ~/Documents/Archives and symlink it")
parser.add_argument('dir', metavar='DIRECTORY', type=str, help="The directory to archive")
parser.add_argument('-d', '--dry', action='store_true')
args = parser.parse_args()
args.dry = True # DEBUG
# archive(args.dir)
ensureLink(args.dir)

View file

@ -21,30 +21,18 @@ function prompt { # text
}
# Don't ask for things that are already there
if which pacaur &> /dev/null; then
PACAUR=1
if which aurman &> /dev/null; then
AURMAN=1
fi
if which bauerbill &> /dev/null; then
BAUERBILL=1
if [ -z $AURMAN ]; then
prompt "Do you want aurman on this machine?"
AURMAN=$?
fi
if [ -z $PACAUR ]; then
prompt "Do you want pacaur on this machine?"
PACAUR=$?
fi
if [ $PACAUR == 1 ]; then
if [ -z $BAUERBILL ]; then
prompt "Do you want bauerbill on this machine?"
BAUERBILL=$?
fi
else
BAUERBILL=0
fi
# COMMON
# Install packages if they aren't installed
function inst {
# Could also use --needed but, meh
for pkg in $*; do
pacman -Q $pkg &> /dev/null
if [ $? == 1 ]; then
@ -69,14 +57,13 @@ inst wget
# Aur
pacman -Q pacaur &> /dev/null
if [[ $PACAUR == 1 && $? == 1 ]]; then
installPKGBUILD "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=cower"
installPKGBUILD "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=pacaur"
pacman -Q aurman &> /dev/null
if [[ $AURMAN == 1 && $? == 1 ]]; then
installPKGBUILD "https://aur.archlinux.org/cgit/aur.git/plain/PKGBUILD?h=aurman"
fi
# Git for /etc
sudo pacman -S etckeeper --noconfirm --needed
inst etckeeper
sudo etckeeper init
sudo etckeeper commit "~/.dotfiles/scripts/install-arch commit"
@ -86,25 +73,11 @@ if pacman -Q pamac &> /dev/null ; then
fi
# Ccache
sudo pacman -S ccache --noconfirm --needed
inst ccache
sudo sed 's|BUILDENV=\(.\+\)!ccache\(.\+\)|BUILDENV=\1ccache\2|' /etc/makepkg.conf -i
# Bauerbill
pacman -Q bauerbill &> /dev/null
if [[ $BAUERBILL == 1 && $? == 1 ]]; then
sudo pacman -Sy
gpg --recv-keys 1D1F0DC78F173680
installPKGBUILD http://xyne.archlinux.ca/projects/reflector/pkgbuild/PKGBUILD
pacaur -S bauerbill --noconfirm --noedit
bauerbill -Su --noconfirm
else
sudo pacman -Syu
fi
# TLP
sudo pacman -S tlp --noconfirm --needed
inst tlp
sudo sed 's|SATA_LINKPWR_ON_BAT=min_power|SATA_LINKPWR_ON_BAT=max_performance|' /etc/default/tlp -i
sudo systemctl enable tlp.service tlp-sleep.service
sudo systemctl disable systemd-rfkill.service systemd-rfkill.socket
@ -117,7 +90,7 @@ echo -e "[Service]\nExecStartPre=/bin/sh -c 'setleds +num < /dev/%I'" | sudo sys
sudo sed "s|#MAKEFLAGS=\"-j2\"|MAKEFLAGS=\"-j$(nproc)\"|" /etc/makepkg.conf -i
# Time synchronisation
sudo pacman -S ntp --noconfirm --needed
inst ntp
sudo systemctl start ntpd
sudo systemctl enable ntpd

View file

@ -54,7 +54,14 @@ if which pacman &> /dev/null; then
function installFileOne { # file
sudo pacman -U "$1"
}
if which pacaur &> /dev/null; then
if which aurman &> /dev/null; then
function altInstallOne { # package
pacman -Q $1 &> /dev/null
if [ $? == 1 ]; then
aurman -S "$1" --noconfirm --noedit
fi
}
elif which pacaur &> /dev/null; then
function altInstallOne { # package
pacman -Q $1 &> /dev/null
if [ $? == 1 ]; then
@ -174,10 +181,11 @@ function systemdUserUnit {
# Common CLI
changeColors monokai
# Utils
inst coreutils man openssl-tool grep sed sh tar
if [ $TERMUX == 1 ]; then
inst coreutils man openssl-tool grep sed sh tar
inst termux-api
if [ $ADMIN == 1 ]; then
inst tsu
@ -186,17 +194,10 @@ fi
inst moreutils screen ncdu lsof htop proxytunnel pv curl wget netcat mosh bash-completion rsync pwgen fzf highlight
# TODO Test those who are on Debian machines and those who aren't
if [ $ARCH == 1 ]; then
inst bash-completion tldr
inst bash-completion
altInst gopass
else
inst pass
wget -qO ~/.local/bin/ https://raw.githubusercontent.com/pepa65/tldr-bash-client/master/tldr
chmod +x ~/.local/bin/tldr
fi
tldr -u
if [[ $ARCH == 1 && $ADMIN == 1 ]]; then
inst pkgfile
sudo systemctl enable pkgfile-update.timer
fi
# Dev
@ -211,16 +212,13 @@ inst git
# Text editor
if [ $TERMUX == 1 ]; then
inst vim-python
elif [ $DEBIAN == 1 ]; then
inst vim-nox
if [ $ADMIN == 0 ]; then
debloc altern vim nox
fi
else
inst vim
inst neovim
if [ $DEBIAN == 1]; then
inst python-neovim pyhon3-neovim
elif [ $ARCH == 1]; then
inst python2-neovim python-neovim
fi
if [ $DEBIAN == 1 ]; then
inst exuberant-ctags
else
@ -233,54 +231,13 @@ if [ $GUI == 1 ]; then
.Xresources.d/configure
# Desktop manager
inst i3 i3lock dunst unclutter xautolock feh numlockx scrot rxvt-unicode xclip
curl "https://raw.githubusercontent.com/FortAwesome/Font-Awesome/a8386aae19e200ddb0f6845b5feeee5eb7013687/fonts/fontawesome-webfont.ttf" > ~/.local/share/fonts/fontawesome-webfont.ttf
inst dunst feh i3-wm i3lock numlockx qutebrowser rofi rxvt-unicode scrot trayer unclutter xautolock xclip
if [ $ARCH == 1 ]; then
inst xorg-xinit
altInst polybar-git autorandr-git keynav-enhanced pacmixer
else
# Compiling polybar
if ! which polybar > /dev/null; then
inst debhelper cmake libxcb-icccm4-dev libxcb-image0-dev libxcb-randr0-dev libx11-dev libxcb1-dev libxcb-util-dev libx11-xcb-dev linux-libc-dev libboost-dev x11proto-core-dev libxcb-ewmh-dev libxft-dev libasound2-dev libiw-dev libmpdclient-dev xcb-proto python-xcbgen libxcb-xkb-dev i3-wm libcairo2-dev libxcb-xrm-dev
# TODO Figure which one are really needed
#inst libasound2 libc6 libgcc1 libiw30 libmpdclient2 libstdc++6 libx11-6 libx11-xcb1 libxcb-ewmh2 libxcb-icccm4 libxcb-randr0 libxcb-xkb1 libxcb1 libxft2
# ↓ really needed
inst libcairo2-dev libxcb-xkb-dev libxcb-randr0-dev xcb-proto libxcb-image0-dev libxcb-icccm4-dev libxcb-ewmh-dev libxcb-util0-dev python-xcbgen
TMP=$(mktemp -d)
git clone --branch 3.0.5 --recursive https://github.com/jaagr/polybar $TMP
mkdir $TMP/build
cd $TMP/build
cmake ..
make -j`nproc`
strip bin/polybar
mv bin/polybar ~/.local/bin/
rm -rf $TMP
fi
fi
if [ $DEBIAN == 1 ]; then
inst suckless-tools keynav
if [ $ADMIN == 0 ]; then
debloc altern dmenu xft
fi
else
inst dmenu
fi
if [ "$(source /etc/os-release; echo $NAME)" == "Manjaro Linux" ]; then
inst menda-themes menda-circle-icon-theme xcursor-menda
fi
# qutebrowser
if [ $DEBIAN == 1 ]; then
inst python3-lxml python-tox python3-pyqt5 python3-pyqt5.qtwebkit python3-pyqt5.qtquick python3-sip python3-jinja2 python3-pygments python3-yaml python3-pyqt5.qtsql libqt5sql5-sqlite python3-pyqt5.qtwebengine python3-pyqt5.qtopengl python3-opengl
TMP_DIR=$(mktemp -d)
$(cd $TMP_DIR; wget https://qutebrowser.org/python3-pypeg2_2.15.2-1_all.deb)
$(cd $TMP_DIR; wget https://github.com/qutebrowser/qutebrowser/releases/download/v0.11.0/qutebrowser_0.11.0-1_all.deb)
instFile $TMP_DIR/*.deb
rm -rf $TMP_DIR
elif [ $ARCH == 1 ]; then
inst qutebrowser qt5-webengine python-opengl
inst xorg-xinit xorg-backlight
altInst lemonbar-xft-git autorandr-git keynav-enhanced pacmixer rofi-pass
elif [ $DEBIAN == 1 ]; then
# TODO autorandr pacmixer rofi-pass
inst lemonbar keynav xbacklight
fi
# Screen filter
@ -294,48 +251,47 @@ if [ $GUI == 1 ]; then
rm $TMP
fi
fi
# Graphical vim
if [ $DEBIAN == 1 ]; then
inst vim-gtk
else
inst gvim
fi
fi
if [ $EXTRA == 1 ]; then
# Extra dev
inst cmake clang llvm npm
inst python-rope
# Extra dev (not on mobile though ^^)
if [ $TERMUX == 0 ]; then
inst cmake clang llvm ccache python-pip
fi
# Extra CLI
inst ffmpeg youtube-dl optipng syncthing ccache mutt
systemdUserUnit syncthing.service
inst ffmpeg optipng syncthing mutt jq
systemdUserUnit syncthing
if [ $ARCH == 1 ]; then
inst jq
altInst pdftk translate-shell git-lfs js-beautify insect visidata-git
insta pandoc youtube-dl translate-shell
altInst insect pdftk visidata
# Orga
# TODO For others
inst vdirsyncer khard
altInst khal todoman offlineimap
inst vdirsyncer khard todoman offlineimap khal
systemdUserUnit vdirsyncer.timer
elif [ $DEBIAN == 1]; then
inst pandoc pdftk visidata translate-shell youtube-dl
else
# translate-shell
curl -L git.io/trans > ~/.local/bin/trans
chmod +x ~/.local/bin/trans
# TODO Others
fi
# Extra GUI
if [ $GUI == 1 ]; then
inst vlc gimp mpd thunar noto-fonts-emoji musescore
inst vlc gimp mpd thunar musescore evince pdfpc texlive-{most,lang}
if [ $ARCH == 1 ]; then
inst simplescreenrecorder
altInst pacmixer xcursor-menda-git menda-themes-git menda-maia-icon-theme vimpc-git mpc ashuffle-git
inst simplescreenrecorder mpc
altInst vimpc-git ashuffle-git ttf-emojione-color
fi
# TODO Others
fi
fi

22
scripts/unziptree Executable file
View file

@ -0,0 +1,22 @@
#!/usr/bin/env python
import os
import subprocess
for root, dirs, files in os.walk("."):
for name in files:
base, ext = os.path.splitext(name)
if ext.lower() != ".zip":
continue
filepath = os.path.join(root, name)
dirpath = os.path.join(root, base)
print(filepath)
os.mkdir(dirpath)
cmd = ["unzip", os.path.realpath(filepath)]
r = subprocess.run(cmd, cwd=dirpath)
r.check_returncode()
os.unlink(filepath)

6
vimrc
View file

@ -58,6 +58,8 @@ Plug 'junegunn/fzf.vim'
Plug 'ervandew/supertab'
Plug 'dpelle/vim-LanguageTool'
Plug 'terryma/vim-smooth-scroll'
Plug 'vim-pandoc/vim-pandoc'
Plug 'vim-pandoc/vim-pandoc-syntax'
call plug#end()
@ -143,6 +145,10 @@ let g:SuperTabContextDefaultCompletionType = "<c-n>"
let g:languagetool_jar = "/usr/share/java/languagetool/languagetool-commandline.jar"
""" vim-pandoc """
let g:pandoc#modules#disabled = ["folding"]
let g:pandoc#syntax#conceal#use = 0
""" VIM SETTINGS """