Skip to content

Instantly share code, notes, and snippets.

@bathtime
Last active March 14, 2018 14:10
Show Gist options
  • Save bathtime/360f405c87afe290c36deedc524dedc8 to your computer and use it in GitHub Desktop.
Save bathtime/360f405c87afe290c36deedc524dedc8 to your computer and use it in GitHub Desktop.
menu for dmenu
// This program gathers and pipes a user-created menu into
// dmenu and allows the user to pick and execute apps:
//
// dmenurc file -> menu -> dmenu -> run chosen app :)
//
// NOTE: dmenu MUST be installed for this program to work!
//
// The goals of this project:
//
// 1. < 100 lines code
// 2. Simple & elegant coding
// 3. Fast & efficient execution.
//
// "Do one thing,
// and do it well."
//
// —Linux Credo
//
// Compile with:
// $ g++ -O2 -Wall menu.cpp -o menu
//
// Make a 9menurc style file in ~/.config/dmenurc with
// application name, a colon, and the application command.
// If no colon is entered, the command will be shown and
// run as its name. Below, 'midori', will run as 'midori'.
//
// Example:
//
// midori
// htop:st -e htop
// surf:surf
// mutt:mutt
//
//
// Run with:
// $ menu
//
#include<experimental/string_view>
#include<iostream>
#include<string>
#include<fstream>
#include<regex>
using namespace std;
std::string exec(const char* cmd) {
std::array<char, 128> buffer;
std::string result;
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
if (!pipe) throw std::runtime_error("popen() failed!");
while (!feof(pipe.get()))
if (fgets(buffer.data(), 128, pipe.get()) != nullptr){
result += buffer.data();
}
// Get ride of extra return carriage
return result.substr(0, result.length() - 1);
}
std::string appSearch(const std::string & searchedApp, const bool & search)
{
std::string s;
std::string appName;
std::string appCommand;
std::string apps = "";
std::size_t colonPos;
ifstream myFile("/home/user/.config/dmenurc");
while (getline (myFile, s))
{
colonPos = s.find(":"); // A colon divides entry name from command
if (colonPos!=std::string::npos)
{
appName = s.substr(0, colonPos);
appCommand = s.substr(colonPos + 1);
}else // App has no colon to delimit command. Run as name.
appName = appCommand = s;
apps += appName + "\\n";
// We found our app, and we have our command to run, so exit and run it!
if (!search && appName == searchedApp)
return appCommand;
}
myFile.close();
// Nothing found, so just send back the parameters entered to be used as a command
if (!search && searchedApp != "")
return searchedApp;
else if (!search && searchedApp == "") // User didn't select an app to run
return "";
// Remove last return carriage from app list
return apps.substr(0, apps.length() - 2);
}
int main(int argc, char* argv[])
{
std::string sysStrCmd = "";
const char * sysCharCmd;
// Prepare dmenu applist; true bool indicates search, and false, run command
sysStrCmd = "echo \"" + appSearch("", true) + "\" | dmenu -b -f";
// Now execute the above command parameters. Save the resulting command to sysStrCmd
if ((sysStrCmd = appSearch(exec(sysCharCmd = sysStrCmd.c_str()), false)) == "")
return 0;
system((sysCharCmd = sysStrCmd.c_str()));
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment