diff --git a/bin/server b/bin/server new file mode 100755 index 0000000..2f8dfd5 --- /dev/null +++ b/bin/server @@ -0,0 +1,262 @@ +#! /usr/bin/env python + +# Shamefully copied from this gist : +# https://gist.github.com/pankajp/280596a5dabaeeceaaaa/ + +# Standard library imports. +import sys + +if sys.version_info[0] < 3: + from SocketServer import ThreadingMixIn + import BaseHTTPServer + from SimpleHTTPServer import SimpleHTTPRequestHandler + from urllib import quote, unquote + from cStringIO import StringIO +else: + import http.server as BaseHTTPServer + from http.server import SimpleHTTPRequestHandler + from socketserver import ThreadingMixIn + from urllib.parse import quote, unquote + from io import BytesIO as cStringIO + +import os +from os.path import (join, exists, abspath, split, splitdrive, isdir) +from os import makedirs, unlink, getcwd, chdir, curdir, pardir, rename, fstat +from shutil import copyfileobj, copytree +import glob +from zipfile import ZipFile +from posixpath import normpath +import re +import cgi +import threading +import socket +import errno + +DATA_DIR = getcwd() + + +class ThreadingHTTPServer(ThreadingMixIn, BaseHTTPServer.HTTPServer): + pass + + +class RequestHandler(SimpleHTTPRequestHandler): + """ Handler to handle POST requests for actions. + """ + + serve_path = DATA_DIR + + def do_GET(self): + """ Overridden to handle HTTP Range requests. """ + self.range_from, self.range_to = self._get_range_header() + if self.range_from is None: + # nothing to do here + return SimpleHTTPRequestHandler.do_GET(self) + f = self.send_range_head() + if f: + self.copy_file_range(f, self.wfile) + f.close() + + def copy_file_range(self, in_file, out_file): + """ Copy only the range in self.range_from/to. """ + in_file.seek(self.range_from) + # Add 1 because the range is inclusive + left_to_copy = 1 + self.range_to - self.range_from + buf_length = 64 * 1024 + bytes_copied = 0 + while bytes_copied < left_to_copy: + read_buf = in_file.read(min(buf_length, left_to_copy - bytes_copied)) + if len(read_buf) == 0: + break + out_file.write(read_buf) + bytes_copied += len(read_buf) + return bytes_copied + + def send_range_head(self): + """Common code for GET and HEAD commands. + + This sends the response code and MIME headers. + + Return value is either a file object (which has to be copied + to the outputfile by the caller unless the command was HEAD, + and must be closed by the caller under all circumstances), or + None, in which case the caller has nothing further to do. + + """ + path = self.translate_path(self.path) + f = None + if isdir(path): + if not self.path.endswith('/'): + # redirect browser - doing basically what apache does + self.send_response(301) + self.send_header("Location", self.path + "/") + self.end_headers() + return None + for index in "index.html", "index.htm": + index = join(path, index) + if exists(index): + path = index + break + else: + return self.list_directory(path) + + if not exists(path) and path.endswith('/data'): + # FIXME: Handle grits-like query with /data appended to path + # stupid grits + if exists(path[:-5]): + path = path[:-5] + + ctype = self.guess_type(path) + try: + # Always read in binary mode. Opening files in text mode may cause + # newline translations, making the actual size of the content + # transmitted *less* than the content-length! + f = open(path, 'rb') + except IOError: + self.send_error(404, "File not found") + return None + + if self.range_from is None: + self.send_response(200) + else: + self.send_response(206) + + self.send_header("Content-type", ctype) + fs = fstat(f.fileno()) + file_size = fs.st_size + if self.range_from is not None: + if self.range_to is None or self.range_to >= file_size: + self.range_to = file_size - 1 + self.send_header("Content-Range", + "bytes %d-%d/%d" % (self.range_from, + self.range_to, + file_size)) + # Add 1 because ranges are inclusive + self.send_header("Content-Length", + (1 + self.range_to - self.range_from)) + else: + self.send_header("Content-Length", str(file_size)) + self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) + self.end_headers() + return f + + def list_directory(self, path): + """Helper to produce a directory listing (absent index.html). + + Return value is either a file object, or None (indicating an + error). In either case, the headers are sent, making the + interface the same as for send_head(). + + """ + try: + list = os.listdir(path) + except os.error: + self.send_error(404, "No permission to list directory") + return None + list.sort(key=lambda a: a.lower()) + f = StringIO() + displaypath = cgi.escape(unquote(self.path)) + f.write('') + f.write("\nDirectory listing for %s\n" % displaypath) + f.write("\n

Directory listing for %s

\n" % displaypath) + f.write("
\n\n
\n\n\n") + length = f.tell() + f.seek(0) + self.send_response(200) + encoding = sys.getfilesystemencoding() + self.send_header("Content-type", "text/html; charset=%s" % encoding) + self.send_header("Content-Length", str(length)) + self.end_headers() + return f + + def translate_path(self, path): + """ Override to handle redirects. + """ + path = path.split('?', 1)[0] + path = path.split('#', 1)[0] + path = normpath(unquote(path)) + words = path.split('/') + words = filter(None, words) + path = self.serve_path + for word in words: + drive, word = splitdrive(word) + head, word = split(word) + if word in (curdir, pardir): continue + path = join(path, word) + return path + + # Private interface ###################################################### + + def _get_range_header(self): + """ Returns request Range start and end if specified. + If Range header is not specified returns (None, None) + """ + + if sys.version_info[0] < 3: + range_header = self.headers.getheader("Range") + else: + range_header = self.headers.get("Range") + + if range_header is None: + return (None, None) + if not range_header.startswith("bytes="): + return (None, None) + regex = re.compile(r"^bytes=(\d+)\-(\d+)?") + rangething = regex.search(range_header) + if rangething: + from_val = int(rangething.group(1)) + if rangething.group(2) is not None: + return (from_val, int(rangething.group(2))) + else: + return (from_val, None) + else: + return (None, None) + + +def get_server(port=8000, next_attempts=0, serve_path=None): + Handler = RequestHandler + if serve_path: + Handler.serve_path = serve_path + while next_attempts >= 0: + try: + httpd = ThreadingHTTPServer(("", port), Handler) + return httpd + except socket.error as e: + if e.errno == errno.EADDRINUSE: + next_attempts -= 1 + port += 1 + else: + raise + + +def main(args=None): + if args is None: + args = sys.argv[1:] + + PORT = 8000 + if len(args) > 0: + PORT = int(args[-1]) + serve_path = DATA_DIR + if len(args) > 1: + serve_path = abspath(args[-2]) + + httpd = get_server(port=PORT, serve_path=serve_path) + + print("serving at port " + str(PORT)) + httpd.serve_forever() + + +if __name__ == "__main__": + main() diff --git a/coc-settings.json b/coc-settings.json index 4942f3d..2c0378f 100644 --- a/coc-settings.json +++ b/coc-settings.json @@ -2,11 +2,11 @@ "languageserver": { "rust": { "command": "rustup", - "args": ["run", "nightly", "rust-analyzer"], + "args": ["run", "stable", "rust-analyzer"], "filetypes": ["rust"], "rootPatterns": ["Cargo.toml"] }, - "elm": { + "elmLS": { "command": "elm-language-server", "filetypes": ["elm"], "rootPatterns": ["elm.json"] diff --git a/init.vim b/init.vim index 07a3a21..84fb88b 100644 --- a/init.vim +++ b/init.vim @@ -196,7 +196,18 @@ autocmd CursorMovedI * if pumvisible() == 0|pclose|endif autocmd InsertLeave * if pumvisible() == 0|pclose|endif " Complete on tab -inoremap pumvisible() ? "\" : "\" +" inoremap pumvisible() ? "\" : "\" +function! s:check_back_space() abort + let col = col('.') - 1 + return !col || getline('.')[col - 1] =~ '\s' +endfunction + +" Insert when previous text is space, refresh completion if not. +inoremap + \ coc#pum#visible() ? coc#pum#next(1): + \ check_back_space() ? "\" : + \ coc#refresh() +inoremap coc#pum#visible() ? coc#pum#prev(1) : "\" " }}} " CUSTOM THINGS DEPENDING ON ENV ####################################{{{ diff --git a/zsh/ohmyzsh/themes/laptop-hostname.zsh-theme b/zsh/ohmyzsh/themes/laptop-hostname.zsh-theme index 56c6ded..e78e058 100644 --- a/zsh/ohmyzsh/themes/laptop-hostname.zsh-theme +++ b/zsh/ohmyzsh/themes/laptop-hostname.zsh-theme @@ -17,13 +17,13 @@ eval PR_BOLD="%{$terminfo[bold]%}" if [[ $UID -ge 1000 ]]; then # normal user # If ssh if [[ -n "$SSH_CLIENT" || -n "$SSH2_CLIENT" ]]; then - eval PR_USER='${PR_GREEN}%n@%M${PR_NO_COLOR}' + eval PR_USER='${PR_GREEN}%n${PR_YELLOW}@${PR_GREEN}%M${PR_NO_COLOR}' eval PR_USER_OP='${PR_GREEN}%#${PR_NO_COLOR}' local PR_ARROW_UP='${PR_GREEN}┌── ${PR_NO_COLOR}' local PR_ARROW_DOWN='${PR_GREEN}└${PR_NO_COLOR}' local PR_PROMPT='$PR_GREEN▷$PR_NO_COLOR' else - eval PR_USER='${PR_MAGENTA}%n@%M${PR_NO_COLOR}' + eval PR_USER='${PR_MAGENTA}%n${PR_YELLOW}@${PR_GREEN}%M${PR_NO_COLOR}' eval PR_USER_OP='${PR_BLUE}%#${PR_NO_COLOR}' local PR_PROMPT='$PR_MAGENTA▷$PR_NO_COLOR' local PR_ARROW_UP='$PR_MAGENTA┌── ${PR_NO_COLOR}'