├── .gitignore ├── LICENSE.md ├── README.md ├── dub.json ├── public └── styles │ └── style.css ├── source ├── app.d └── pipedprocess.d └── views └── index.dt /.gitignore: -------------------------------------------------------------------------------- 1 | *.[oa] 2 | *.so 3 | *.lib 4 | *.dll 5 | .*.sw* 6 | .dub 7 | docs.json 8 | __dummy.html 9 | *.o 10 | *.obj 11 | *.sublime-project 12 | /*.exe 13 | /*.sublime-workspace 14 | /source/sftp-config.json 15 | sftp-config.json 16 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 KrzaQ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | A reasonable donation shall be made to bitcoin address `1krzaqocAtXRpTohTGMUV41ZT49o9Vu2k` 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # What is this? 2 | - - - 3 | A web wrapper for clang-format. You can see it in action [here](http://format.krzaq.cc/). 4 | 5 | # Installation 6 | - - - 7 | Like any dub project. 8 | 9 | # License 10 | - - - 11 | Copyright (C) 2014 KrzaQ 12 | 13 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 16 | 17 | A reasonable donation shall be made to bitcoin address `1krzaqocAtXRpTohTGMUV41ZT49o9Vu2k` 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /dub.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cppformat", 3 | "description": "A simple vibe.d server application.", 4 | "copyright": "Copyright © 2014, krzaq", 5 | "authors": ["krzaq"], 6 | "dependencies": { 7 | "vibe-d": "~>0.7.23" 8 | }, 9 | "versions": ["VibeDefaultMain"] 10 | } 11 | -------------------------------------------------------------------------------- /public/styles/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 10pt; 3 | font-family: Arial, Helvetica; 4 | font-weight: normal; 5 | background-color: #303030; 6 | color: #808080; 7 | } 8 | 9 | /*legend {font-size: 10pt; font-family: Arial, Helvetica; font-weight: bold; color: #808080; }*/ 10 | 11 | #main { 12 | margin-left: auto; 13 | margin-right: auto; 14 | width: 70%; 15 | } 16 | 17 | #data { 18 | width: 100%; 19 | height: 600px; 20 | color: #CCCCCC; 21 | font-style: italic; 22 | background-color: #282828; 23 | } 24 | 25 | #styleLabel { 26 | /*text-align: right;*/ 27 | float: right; 28 | } 29 | 30 | #styleSelect { 31 | /*text-align: right;*/ 32 | float: right; 33 | } 34 | 35 | #submitButton { 36 | /*text-align: right;*/ 37 | float: right; 38 | } 39 | 40 | #footer { 41 | text-align: center; 42 | color: #EEE; 43 | font-size: x-small; 44 | } 45 | 46 | #footer a:link { 47 | color: #DDD; 48 | } 49 | 50 | #footer a:visited { 51 | color: #BBB; 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /source/app.d: -------------------------------------------------------------------------------- 1 | import vibe.d; 2 | 3 | shared static this() 4 | { 5 | auto settings = new HTTPServerSettings; 6 | settings.port = 8080; 7 | settings.bindAddresses = ["::1", "0.0.0.0"]; 8 | 9 | auto router = new URLRouter; 10 | 11 | router.registerWebInterface(new WebInterface); 12 | router.get("*", serveStaticFiles("public/")); 13 | 14 | listenHTTP(settings, router); 15 | } 16 | 17 | class WebInterface { 18 | 19 | this(){ 20 | styles = [ "LLVM", "Google", "Chromium", "Mozilla", "WebKit", "file"]; 21 | } 22 | 23 | void index() 24 | { 25 | auto code = ""; 26 | auto selectedStyle = "WebKit"; 27 | render!("index.dt", styles, code, selectedStyle); 28 | } 29 | 30 | void post(string style, string code) 31 | { 32 | import std.algorithm; 33 | import std.file; 34 | import std.conv; 35 | import std.math; 36 | import std.process; 37 | 38 | import pipedprocess; 39 | 40 | PipedProcess p = new PipedProcess("clang-format", ["-style="~style]); 41 | 42 | p.stdin.write(code); 43 | p.stdin.finalize; 44 | 45 | code = ""; 46 | 47 | for(ulong toRead = 0; toRead > 0 || p.stdout.connected; toRead = p.stdout.leastSize){ 48 | ubyte[] buf = new ubyte[toRead]; 49 | p.stdout.read(buf); 50 | code ~= buf; 51 | } 52 | 53 | //auto pipes = pipeProcess(["clang-format", "-style="~style], Redirect.stdout | Redirect.stdin); 54 | //scope(exit) wait(pipes.pid); 55 | 56 | //pipes.stdin.write(code); 57 | //pipes.stdin.close; 58 | //pipes.pid.wait; 59 | 60 | //code = pipes.stdout.byLine.joiner.to!string; 61 | 62 | string selectedStyle = style; 63 | 64 | render!("index.dt", styles, code, selectedStyle); 65 | } 66 | 67 | string[] styles; 68 | } 69 | -------------------------------------------------------------------------------- /source/pipedprocess.d: -------------------------------------------------------------------------------- 1 | import core.thread; 2 | 3 | import std.datetime; 4 | import std.process; 5 | 6 | import vibe.d; 7 | import vibe.stream.stdio; 8 | 9 | class PipedProcess { 10 | 11 | private { 12 | ProcessPipes m_pipes; 13 | StdFileStream m_stdout; 14 | StdFileStream m_stdin; 15 | Thread m_waitThread; 16 | SysTime m_startTime; 17 | SysTime m_endTime; 18 | 19 | core.sync.mutex.Mutex m_statusMutex; 20 | core.sync.condition.Condition m_statusCondition; 21 | bool m_running = true; 22 | bool m_failed; 23 | int m_returnCode; 24 | string m_command; 25 | string[] m_args; 26 | void delegate()[] m_exitCallbacks; 27 | } 28 | 29 | string name; 30 | 31 | this(string cmd, string[] args) 32 | { 33 | m_command = cmd; 34 | m_args = args; 35 | m_startTime = Clock.currTime(); 36 | m_statusMutex = new core.sync.mutex.Mutex; 37 | m_statusCondition = new TaskCondition(m_statusMutex); 38 | m_stdin = new StdFileStream(false, true); 39 | m_stdout = new StdFileStream(true, false); 40 | 41 | logDebugV("Waiting for process start"); 42 | auto thr = new Thread(&waitThreadFunc); 43 | thr.name = "PipedProcess executor"; 44 | thr.start(); 45 | logDebugV(" ... process running"); 46 | runTask(&waitTaskFunc); 47 | } 48 | 49 | @property SysTime startTime() { synchronized(m_statusMutex) return m_startTime; } 50 | @property SysTime endTime() { synchronized(m_statusMutex) return m_endTime; } 51 | 52 | @property bool running() const { synchronized(m_statusMutex) return m_running; } 53 | @property bool failed() const { synchronized(m_statusMutex) return m_failed; } 54 | @property int exitCode() const { synchronized(m_statusMutex) return m_returnCode; } 55 | 56 | @property OutputStream stdin() { synchronized(m_statusMutex) return m_stdin; } 57 | @property ConnectionStream stdout() { synchronized(m_statusMutex) return m_stdout; } 58 | 59 | void kill() 60 | { 61 | m_pipes.pid.kill(); 62 | } 63 | 64 | void performOnExit(void delegate() del) 65 | { 66 | if (!m_running) del(); 67 | else m_exitCallbacks ~= del; 68 | } 69 | 70 | void join() 71 | { 72 | synchronized (m_statusMutex) { 73 | while (m_running) 74 | m_statusCondition.wait(); 75 | } 76 | } 77 | 78 | private void waitTaskFunc() 79 | { 80 | synchronized (m_statusMutex) { 81 | while (m_running) 82 | m_statusCondition.wait(); 83 | } 84 | foreach (del; m_exitCallbacks) del(); 85 | } 86 | 87 | private void waitThreadFunc() 88 | { 89 | scope(exit){ 90 | synchronized (m_statusMutex) { 91 | m_endTime = Clock.currTime(); 92 | m_running = false; 93 | } 94 | m_statusCondition.notifyAll(); 95 | } 96 | try { 97 | logDebug("pipeProcess %s %s", m_command, m_args); 98 | auto pipes = pipeProcess(m_command ~ m_args, Redirect.stdin|Redirect.stdout|Redirect.stderrToStdout); 99 | m_stdin.setup(pipes.stdin); 100 | m_stdout.setup(pipes.stdout); 101 | synchronized(m_statusMutex){ 102 | m_pipes = pipes; 103 | } 104 | m_statusCondition.notifyAll(); 105 | auto ret = m_pipes.pid.wait(); 106 | synchronized (m_statusMutex) 107 | m_returnCode = ret; 108 | logTrace("closing pipes"); 109 | m_stdin.finalize(); 110 | //m_pipes.stdin.close(); 111 | //m_pipes.stdout.close(); 112 | } catch (Exception e) { 113 | import std.encoding : sanitize; 114 | logError("Failed to execute process: %s", e.msg); 115 | logDiagnostic("Full exception: %s", e.toString().sanitize()); 116 | synchronized (m_statusMutex) 117 | m_failed = true; 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /views/index.dt: -------------------------------------------------------------------------------- 1 | - void css(string file) 2 | link(rel= 'stylesheet', type='text/css', href='styles/#{file}.css') 3 | 4 | doctype html 5 | html 6 | head 7 | title C++ code formatter (based on clang-format) 8 | - css("style"); 9 | body 10 | #main 11 | form(action="/", method="POST") 12 | textarea(name="code")#data #{code} 13 | br 14 | button(type="submit")#submitButton Format! 15 | select(name="style")#styleSelect 16 | - foreach(o; styles) 17 | - if(o == selectedStyle) 18 | option(value=o, selected) #{o} 19 | - else 20 | option(value=o) #{o} 21 | span#styleLabel Style: 22 | br 23 | #footer 24 | :markdown 25 | [C++ online code formatter](https://github.com/KrzaQ/cppformat) © 2014 by [KrzaQ](http://dev.krzaq.cc) 26 | 27 | Powered by [vibe.d](http://vibed.org/), [the D language](http://dlang.org) and [clang-format](http://clang.llvm.org/docs/ClangFormat.html) 28 | --------------------------------------------------------------------------------