mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
281 lines
7.8 KiB
C++
281 lines
7.8 KiB
C++
////////////////////////////////////////////////////////////////////////////////
|
||
// Taskwarrior Lua API
|
||
//
|
||
// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez.
|
||
// All rights reserved.
|
||
//
|
||
// This program is free software; you can redistribute it and/or modify it under
|
||
// the terms of the GNU General Public License as published by the Free Software
|
||
// Foundation; either version 2 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 General Public License for more
|
||
// details.
|
||
//
|
||
// You should have received a copy of the GNU General Public License along with
|
||
// this program; if not, write to the
|
||
//
|
||
// Free Software Foundation, Inc.,
|
||
// 51 Franklin Street, Fifth Floor,
|
||
// Boston, MA
|
||
// 02110-1301
|
||
// USA
|
||
//
|
||
// -------------
|
||
//
|
||
// Copyright © 1994–2008 Lua.org, PUC-Rio.
|
||
//
|
||
// 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:
|
||
//
|
||
// The above copyright notice and this permission notice shall be included in
|
||
// all copies or substantial portions of the Software.
|
||
//
|
||
// 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.
|
||
//
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
#define L10N // Localization complete.
|
||
|
||
#include <algorithm>
|
||
#include <iostream>
|
||
#include <Context.h>
|
||
#include <API.h>
|
||
#include <text.h>
|
||
#include <i18n.h>
|
||
|
||
extern Context context;
|
||
|
||
#ifdef HAVE_LIBLUA
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
static int api_task_header_message (lua_State* L)
|
||
{
|
||
std::string message = luaL_checkstring (L, 1);
|
||
context.header (message);
|
||
return 0;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
static int api_task_footnote_message (lua_State* L)
|
||
{
|
||
std::string message = luaL_checkstring (L, 1);
|
||
context.footnote (message);
|
||
return 0;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
static int api_task_debug_message (lua_State* L)
|
||
{
|
||
std::string message = luaL_checkstring (L, 1);
|
||
context.debug (message);
|
||
return 0;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// Causes the shell or interactive mode task to exit. Ordinarily this does not
|
||
// occur.
|
||
static int api_task_exit (lua_State*)
|
||
{
|
||
// TODO Is this the correct exception? How does the shell handle this?
|
||
std::cout << STRING_API_EXITING << std::endl;
|
||
exit (0);
|
||
return 0;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// DOM reads.
|
||
static int api_task_get (lua_State* L)
|
||
{
|
||
std::string name = luaL_checkstring (L, 1);
|
||
try
|
||
{
|
||
lua_pushstring (L, context.dom.get (name).c_str ());
|
||
}
|
||
catch (...)
|
||
{
|
||
// TODO Error!
|
||
lua_pushstring (L, "");
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
// DOM writes.
|
||
static int api_task_set (lua_State* L)
|
||
{
|
||
std::string name = luaL_checkstring (L, 1);
|
||
std::string value = luaL_checkstring (L, 2);
|
||
|
||
try
|
||
{
|
||
context.dom.set (name, value);
|
||
}
|
||
catch (...)
|
||
{
|
||
// TODO Error!
|
||
lua_pushstring (L, "");
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
API::API ()
|
||
: L (NULL)
|
||
{
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
API::~API ()
|
||
{
|
||
if (L)
|
||
{
|
||
lua_close (L);
|
||
L = NULL;
|
||
}
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
void API::initialize ()
|
||
{
|
||
// Initialize Lua.
|
||
L = lua_open ();
|
||
luaL_openlibs (L); // TODO Error handling
|
||
|
||
// Register all the API functions in Lua global space.
|
||
lua_pushcfunction (L, api_task_header_message); lua_setglobal (L, "task_header_message");
|
||
lua_pushcfunction (L, api_task_footnote_message); lua_setglobal (L, "task_footnote_message");
|
||
lua_pushcfunction (L, api_task_debug_message); lua_setglobal (L, "task_debug_message");
|
||
lua_pushcfunction (L, api_task_exit); lua_setglobal (L, "task_exit");
|
||
lua_pushcfunction (L, api_task_get); lua_setglobal (L, "task_get");
|
||
lua_pushcfunction (L, api_task_set); lua_setglobal (L, "task_set");
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
bool API::callProgramHook (
|
||
const std::string& file,
|
||
const std::string& function)
|
||
{
|
||
loadFile (file);
|
||
|
||
// Get function.
|
||
lua_getglobal (L, function.c_str ());
|
||
if (!lua_isfunction (L, -1))
|
||
{
|
||
lua_pop (L, 1);
|
||
throw format (STRING_API_NOFUNC, function);
|
||
}
|
||
|
||
// Make call.
|
||
if (lua_pcall (L, 0, 2, 0) != 0)
|
||
throw format (STRING_API_ERROR_CALLING, function, lua_tostring (L, -1));
|
||
|
||
// Call successful - get return values.
|
||
if (!lua_isnumber (L, -2))
|
||
throw format (STRING_API_ERROR_FAIL, function);
|
||
|
||
if (!lua_isstring (L, -1) && !lua_isnil (L, -1))
|
||
throw format (STRING_API_ERROR_NORET, function);
|
||
|
||
int rc = lua_tointeger (L, -2);
|
||
const char* message = lua_tostring (L, -1);
|
||
|
||
if (rc == 0)
|
||
{
|
||
if (message)
|
||
context.footnote (format (STRING_API_WARNING, message));
|
||
}
|
||
else
|
||
{
|
||
if (message)
|
||
throw std::string (message);
|
||
}
|
||
|
||
lua_pop (L, 1);
|
||
return rc == 0 ? true : false;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
bool API::callTaskHook (
|
||
const std::string& file,
|
||
const std::string& function,
|
||
Task& task)
|
||
{
|
||
loadFile (file);
|
||
|
||
// Save the task for reference via the API.
|
||
current = task;
|
||
|
||
// Get function.
|
||
lua_getglobal (L, function.c_str ());
|
||
if (!lua_isfunction (L, -1))
|
||
{
|
||
lua_pop (L, 1);
|
||
throw format (STRING_API_NOFUNC, function);
|
||
}
|
||
|
||
// Prepare args.
|
||
lua_pushnumber (L, current.id);
|
||
|
||
// Make call.
|
||
if (lua_pcall (L, 1, 2, 0) != 0)
|
||
throw format (STRING_API_ERROR_CALLING, function, lua_tostring (L, -1));
|
||
|
||
// Call successful - get return values.
|
||
if (!lua_isnumber (L, -2))
|
||
throw format (STRING_API_ERROR_FAIL, function);
|
||
|
||
if (!lua_isstring (L, -1) && !lua_isnil (L, -1))
|
||
throw format (STRING_API_ERROR_NORET, function);
|
||
|
||
int rc = lua_tointeger (L, -2);
|
||
const char* message = lua_tostring (L, -1);
|
||
|
||
if (rc == 0)
|
||
{
|
||
if (message)
|
||
context.footnote (format (STRING_API_WARNING, message));
|
||
}
|
||
else
|
||
{
|
||
if (message)
|
||
throw std::string (message);
|
||
}
|
||
|
||
lua_pop (L, 1);
|
||
return rc == 0 ? true : false;
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
void API::loadFile (const std::string& file)
|
||
{
|
||
// If the file is not loaded.
|
||
if (std::find (loaded.begin (), loaded.end (), file) == loaded.end ())
|
||
{
|
||
// Load the file, if possible.
|
||
if (luaL_loadfile (L, file.c_str ()) || lua_pcall (L, 0, 0, 0))
|
||
throw format (STRING_API_ERROR, lua_tostring (L, -1));
|
||
|
||
// Mark this as loaded, so as to not bother again.
|
||
loaded.push_back (file);
|
||
}
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////////////
|
||
|
||
#endif
|
||
|